@bicharts/chart-host 0.6.47 → 0.6.49

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/react.mjs CHANGED
@@ -7,7 +7,7 @@ import {
7
7
  loadGeo,
8
8
  syncMemberSelection,
9
9
  toSourceRows
10
- } from "./chunk-XWVIYCMM.mjs";
10
+ } from "./chunk-53OX7DYN.mjs";
11
11
  import "./chunk-A2GMXZP7.mjs";
12
12
  import "./chunk-GHODWOAL.mjs";
13
13
 
@@ -5,6 +5,8 @@ export interface MarkCensus {
5
5
  legendMarkCount: number;
6
6
  /** What the chart built. `html` is a first-class answer, not a failure — see below. */
7
7
  containerKind: "svg" | "html" | "empty";
8
+ /** The chart declared (NO_ROW_MARKS_ATTR) that it draws no per-row marks by design. */
9
+ declaresNoRowMarks: boolean;
8
10
  }
9
11
  /**
10
12
  * Count what the render actually left behind.
@@ -45,6 +47,13 @@ export interface BlankVerdictInput {
45
47
  * evidence-free and must not return a verdict.
46
48
  */
47
49
  contractUntagged?: boolean;
50
+ /**
51
+ * The chart declared that it draws no per-row marks by design (censusMarks reports it from
52
+ * NO_ROW_MARKS_ATTR). A what-if predictor draws one model, not a mark per row, so "no marks"
53
+ * is its correct picture. The declaration sits in the chart's working path, so a chart that
54
+ * bailed to its no-data branch never carries it and is still judged.
55
+ */
56
+ declaresNoRowMarks?: boolean;
48
57
  }
49
58
  /**
50
59
  * Did this render paint nothing, against data that had something to paint?
@@ -1,24 +1,6 @@
1
- /**
2
- * A standing chart-type pick, checked against a FRESH qualify list.
3
- *
4
- * A reader's explicit pick can outlive the generate it was made for - a host that keeps it across a
5
- * refusal that spent nothing, or one whose pick is a standing control by design. Either way the fields
6
- * can change underneath it, and a pick the data no longer supports would otherwise cost a generate to
7
- * discover: the substitution warning arrives after the credit, not before it.
8
- *
9
- * ONLY AGAINST A FRESH LIST, and only against the server's own answer. The list is what the qualify
10
- * endpoint says fits the data as it is now; checking the pick against a client-side re-implementation of
11
- * the shape gates would be a second opinion quietly disagreeing with the engine.
12
- *
13
- * AN EMPTY LIST IS NOT EVIDENCE THE PICK DIED. It is the shape qualifying for nothing, which has its own
14
- * message and its own fix; dropping the pick there would add a second, misleading sentence.
15
- *
16
- * A DROP IS ALWAYS SAID. The message names the type and what the pick went back to, so a pick never
17
- * disappears silently. `offered` is every name the host would let the reader pick right now - a host whose
18
- * list also offers poor-fit types to pick anyway passes those too, because the pick is still choosable.
19
- */
20
1
  export interface ChartPickReconciliation {
21
- /** The pick after reconciling: the original (trimmed) when still offered, else "" (no pick). */
2
+ /** The pick after reconciling: the original (trimmed) when still offered under its own spelling, the
3
+ * OFFERED spelling when it is offered only under the loose key, else "" (no pick). */
22
4
  pick: string;
23
5
  /** True when a pick was dropped because the fresh list no longer offers it. */
24
6
  dropped: boolean;
@@ -1,4 +1,4 @@
1
- export declare const HOST_CONTRACT_VERSION = "1.12.0";
1
+ export declare const HOST_CONTRACT_VERSION = "1.13.0";
2
2
  export type GeoPointPrecision = "latlon" | "city" | "zip3" | "state" | "country";
3
3
  /** Every valid tier, ordered most precise → coarsest. Runtime form of GeoPointPrecision. */
4
4
  export declare const GEO_POINT_PRECISIONS: readonly GeoPointPrecision[];
@@ -13,6 +13,8 @@ export declare const AXIS_FILTER_CLASS = "d3-axis-filter";
13
13
  export declare const LIFT_SELECTED_CLASS = "d3-lift-selected";
14
14
  export declare const CONTROL_CLASS = "lch-control";
15
15
  export declare const ROW_IDX_ATTR = "data-row-idx";
16
+ export declare const NO_ROW_MARKS_ATTR = "data-lch-no-row-marks";
17
+ export declare const SNAPSHOT_SVG_ATTR = "data-lch-snapshot";
16
18
  export declare const XFILTER_REFRESH_EVENT = "llm-xfilter-refresh";
17
19
  export declare const CONTAINER_SLOT_ANIM_STOP = "__llmAnimStop";
18
20
  export declare const CONTAINER_SLOT_XF_CLEAR = "__llmXfClear";
@@ -71,6 +73,10 @@ export declare const COLOR_SCALE_SELF_CLAMP_PCT_MAX = 100;
71
73
  export type TimelineStyle = "" | "line" | "boxes";
72
74
  export type FlipMode = "" | "single" | "all" | "both";
73
75
  export declare const FLIP_MODE_DEFAULT: FlipMode;
76
+ export declare const FLIP_INTERVAL_MIN_MS = 500;
77
+ export declare const FLIP_INTERVAL_MAX_MS = 120000;
78
+ export type FlipDirection = "horizontal" | "vertical";
79
+ export declare const FLIP_DIRECTION_DEFAULT: FlipDirection;
74
80
  export type ApproximatePositions = "mark" | "aggregate" | "skip";
75
81
  export declare const APPROXIMATE_POSITIONS_DEFAULT: ApproximatePositions;
76
82
  export type ValueAxisBaseline = "zero" | "fit" | "auto";
@@ -144,6 +150,7 @@ export interface RenderOptions {
144
150
  flipSync?: boolean;
145
151
  flipIntervalMs?: number;
146
152
  flipMode?: FlipMode;
153
+ flipDirection?: FlipDirection;
147
154
  cardBackgroundColor?: string;
148
155
  onSelect?: (rowIdxs: number[]) => void;
149
156
  /**
@@ -1,4 +1,4 @@
1
- export { HOST_CONTRACT_VERSION, GEO_POINT_PRECISIONS, MARK_CLASS, LEGEND_MARK_CLASS, AXIS_FILTER_CLASS, ROW_IDX_ATTR, LIFT_SELECTED_CLASS, CONTROL_CLASS, XFILTER_REFRESH_EVENT, CONTAINER_SLOT_ANIM_STOP, CONTAINER_SLOT_XF_CLEAR, CONTAINER_SLOT_INITIAL_XF_MARK, CONTAINER_SLOT_UI_STATE, VIEW_ONLY_UI_STATE_KEYS, withoutViewOnlyKeys, HOST_CONTAINER_CLASS, SELECTION_ACTIVE_CLASS, MARK_SELECTED_CLASS, ACTIVE_TICK_CLASS, DIM_OPACITY_VAR, DIM_OPACITY_DEFAULT, chartOwnsTimeline, periodTickSuppressesFeedback, ANIM_PLAY_SPEED_DEFAULT, ANIM_PLAY_SPEED_MIN, ANIM_PLAY_SPEED_MAX, ANIM_LOOP_DELAY_DEFAULT, ANIM_LOOP_DELAY_MIN, ANIM_MAX_IDEAL_FRAMES_DEFAULT, ANIM_MAX_IDEAL_FRAMES_MIN, ANIM_MAX_IDEAL_FRAMES_MAX, ANIMATION_OPTION_KEYS, COLOR_SCALE_SELF_CLAMP_PCT_DEFAULT, COLOR_SCALE_SELF_CLAMP_PCT_MIN, COLOR_SCALE_SELF_CLAMP_PCT_MAX, FLIP_MODE_DEFAULT, APPROXIMATE_POSITIONS_DEFAULT, VALUE_AXIS_BASELINE_DEFAULT, SEASONAL_MARKERS_DEFAULT, MAX_MAP_POINTS_DEFAULT, type GeoPointPrecision, type GeoMapKind, type TimelineStyle, type FlipMode, type ApproximatePositions, type ValueAxisBaseline, type SeasonalMarkers, type ColorScaleScope, type RenderOptions, type ViewStateProvider, type ChartControlChange, } from "./contract";
1
+ export { HOST_CONTRACT_VERSION, GEO_POINT_PRECISIONS, MARK_CLASS, LEGEND_MARK_CLASS, AXIS_FILTER_CLASS, ROW_IDX_ATTR, LIFT_SELECTED_CLASS, CONTROL_CLASS, NO_ROW_MARKS_ATTR, SNAPSHOT_SVG_ATTR, XFILTER_REFRESH_EVENT, CONTAINER_SLOT_ANIM_STOP, CONTAINER_SLOT_XF_CLEAR, CONTAINER_SLOT_INITIAL_XF_MARK, CONTAINER_SLOT_UI_STATE, VIEW_ONLY_UI_STATE_KEYS, withoutViewOnlyKeys, HOST_CONTAINER_CLASS, SELECTION_ACTIVE_CLASS, MARK_SELECTED_CLASS, ACTIVE_TICK_CLASS, DIM_OPACITY_VAR, DIM_OPACITY_DEFAULT, chartOwnsTimeline, periodTickSuppressesFeedback, ANIM_PLAY_SPEED_DEFAULT, ANIM_PLAY_SPEED_MIN, ANIM_PLAY_SPEED_MAX, ANIM_LOOP_DELAY_DEFAULT, ANIM_LOOP_DELAY_MIN, ANIM_MAX_IDEAL_FRAMES_DEFAULT, ANIM_MAX_IDEAL_FRAMES_MIN, ANIM_MAX_IDEAL_FRAMES_MAX, ANIMATION_OPTION_KEYS, COLOR_SCALE_SELF_CLAMP_PCT_DEFAULT, COLOR_SCALE_SELF_CLAMP_PCT_MIN, COLOR_SCALE_SELF_CLAMP_PCT_MAX, FLIP_MODE_DEFAULT, FLIP_INTERVAL_MIN_MS, FLIP_INTERVAL_MAX_MS, FLIP_DIRECTION_DEFAULT, APPROXIMATE_POSITIONS_DEFAULT, VALUE_AXIS_BASELINE_DEFAULT, SEASONAL_MARKERS_DEFAULT, MAX_MAP_POINTS_DEFAULT, type GeoPointPrecision, type GeoMapKind, type TimelineStyle, type FlipMode, type FlipDirection, type ApproximatePositions, type ValueAxisBaseline, type SeasonalMarkers, type ColorScaleScope, type RenderOptions, type ViewStateProvider, type ChartControlChange, } from "./contract";
2
2
  export { resolveOptions, type ResolveOptionsInput } from "./defaults";
3
3
  export { OPTIONS_VOCABULARY, LIVE_OPTION_KEYS, MAX_MAP_POINTS_MIN, MAX_MAP_POINTS_MAX, LIMIT_COUNT_MAX, wireLimitCount, type OptionVocabularyEntry, type OptionTiming, type OptionWire, type OptionKey, } from "./optionsVocabulary";
4
4
  export { loadGeo, geoFromCache, registerGeo, registerGeoAsset, geoAssetFor, clearGeoCache, type GeoAssetName, } from "./geoLazy";
@@ -11,19 +11,19 @@ export { createChartHost, compileRenderFn, stripEsmExports, requiredD3Plugins, e
11
11
  export { createChartGroup, toSourceRows, syncMemberSelection, type ChartGroup, type ChartGroupMember, type ChartGroupSelection, type ChartGroupChange, type ChartGroupMemberOptions, type ChartGroupSourceOptions, type ChartGroupPayload } from "./group";
12
12
  export { createMarkResolver, isInsideControl, rowIdxsFromMark, nextSelection, collectD3GlyphCenters, clearSelectionGlyphs, paintSelectionGlyphs, SELECTION_GLYPH_CLASS, type MarkResolver, type MarkResolverEnv, type GlyphCenter, type SelectionGlyphStyle, type SelectionModifiers, } from "./selection";
13
13
  export { planTrivialChart, compileTrivialSource, type TrivialPlan, type TrivialShapeKind } from "./trivial";
14
- export { captureSvgSnapshot, svgToDataUrl, svgNaturalSize, rasterizeSvgToPngDataUrl, type SnapshotOptions } from "./snapshot";
14
+ export { captureSvgSnapshot, svgToDataUrl, svgNaturalSize, rasterizeSvgToPngDataUrl, tableHostOf, chartSvgOf, htmlToSvgDataUrl, htmlNaturalSize, type SnapshotOptions } from "./snapshot";
15
15
  export { shouldReview, buildReviewWire, bareBase64, actionFor, type ReviewGate, type ReviewWire, type ReviewVerdict, type ReviewAction } from "./review";
16
16
  export { askApplyImprovements, type ReviewDialogOptions, type ReviewDialogText } from "./reviewDialog";
17
17
  export { mountProductFeedbackBox, normaliseProductFeedbackText, productFeedbackSendable, buildProductFeedbackPayload, PRODUCT_FEEDBACK_MAX_CHARS, PRODUCT_FEEDBACK_MIN_CHARS, type ProductFeedbackBox, type ProductFeedbackBoxOptions, type ProductFeedbackText, type ProductFeedbackSendResult, type ProductFeedbackPayload, type ProductFeedbackIdentity, type ProductFeedbackHost, } from "./productFeedback";
18
18
  export { qualifyGroupHeadingFor, newQualifyGroupState, type QualifyGroupRow, type QualifyGroupState, type QualifyGroupHeading, orderRefusalsForDisplay, refusalIsSelectable, hasRefusalsToShow, qualifyRefusalHeadingFor, newQualifyRefusalGroupState, qualifyRefusalReason, QUALIFY_REFUSAL_UNSPECIFIED, type QualifyRefusalRow, type QualifyRefusalGroupState, type QualifyRefusalHeading, } from "./qualifyGroups";
19
19
  export { qualifyPick, qualifyAuto, qualifyCancel, launchGenerates, launchFavorStyle, chooserFitsViewport, shouldOpenChooserOnGenerate, shouldOpenInlineChooserOnGenerate, canConfirmLaunch, confirmLaunch, qualifyFailureFallsOpen, CHOOSER_MIN_WIDTH_PX, CHOOSER_MIN_HEIGHT_PX, type QualifyLaunchOutcome, type ChooserGateInput, } from "./qualifyLaunch";
20
- export { normalizeFilterTerm, filterQualifyRows, readQualifyChartRow, readQualifyRefusalRow, filterFitsChooser, listNeedsFilter, qualifyFilterGate, inlineFilterGate, FILTER_MIN_TERM_CHARS, FILTER_ROW_PX, FILTER_MIN_WIDTH_PX, FILTER_MIN_HEIGHT_PX, INLINE_FILTER_MIN_ROWS, computeQualifyFilterView, qualifyFilterCountText, type QualifyFilterTier, type QualifyFilterResult, type QualifyFilterRead, type QualifyFilterGateReason, type QualifyFilterGateInput, type QualifyFilterRow, type QualifyFilterGroup, type QualifyFilterView, type QualifyFilterNoteKind, } from "./qualifyFilter";
20
+ export { normalizeFilterTerm, filterQualifyRows, readQualifyChartRow, readQualifyRefusalRow, DEFAULT_FILTER_MATCH_STYLE, filterMatchStyleOf, type FilterMatchStyle, filterFitsChooser, listNeedsFilter, qualifyFilterGate, inlineFilterGate, FILTER_MIN_TERM_CHARS, FILTER_ROW_PX, FILTER_MIN_WIDTH_PX, FILTER_MIN_HEIGHT_PX, INLINE_FILTER_MIN_ROWS, computeQualifyFilterView, qualifyFilterCountText, type QualifyFilterTier, type QualifyFilterResult, type QualifyFilterRead, type QualifyFilterGateReason, type QualifyFilterGateInput, type QualifyFilterRow, type QualifyFilterGroup, type QualifyFilterView, type QualifyFilterNoteKind, } from "./qualifyFilter";
21
21
  export { computeSelectionCard, normaliseAggregation, type SelectionCardModel, type SelectionCardLine, type SelectionCardOptions, } from "./selectionCard";
22
22
  export { formatSourceDate, formatSourceDateFor, isExcelDateFormat, type SourceFormats, type SourceFormatDialect, type SourceDateOptions, } from "./sourceDateFormat";
23
23
  export { composeSummaryText } from "./summaryText";
24
24
  export { ensureCrossfilterHitTargets, type HitTargetReport } from "./hitTargets";
25
- export { applyLabelContrast, LABEL_CONTRAST_DONE_ATTR, LABEL_CONTRAST_CAP, type LabelContrastOptions, type LabelContrastReport, } from "./labelContrastDom";
26
- export { decideLabelColor, toRGBA, compositeOver, relativeLuminance, contrastRatio, isPillBackdropAlpha, pillBacksGlyph, backingHoldsGlyph, cellSuppressesNormalize, glyphSampleGrid, DARK_TEXT, LIGHT_TEXT, MIN_CONTRAST, WHITE_TEXT_BG_LUM, PILL_MIN_ALPHA, PILL_OPAQUE_ALPHA, PILL_MIN_COVERAGE, PAGE_MATCH_TOLERANCE, BACKING_MAJORITY, GLYPH_SAMPLE_N, type LabelDecision, } from "./labelContrast";
25
+ export { applyLabelContrast, LABEL_CONTRAST_DONE_ATTR, LABEL_CONTRAST_CAP, LABEL_PILL_CLASS, type LabelContrastOptions, type LabelContrastReport, } from "./labelContrastDom";
26
+ export { decideLabelColor, toRGBA, compositeOver, relativeLuminance, contrastRatio, isPillBackdropAlpha, pillBacksGlyph, backingHoldsGlyph, cellSuppressesNormalize, glyphSampleGrid, DARK_TEXT, LIGHT_TEXT, MIN_CONTRAST, WHITE_TEXT_BG_LUM, PILL_MIN_ALPHA, PILL_OPAQUE_ALPHA, PILL_MIN_COVERAGE, PAGE_MATCH_TOLERANCE, BACKING_MAJORITY, GLYPH_SAMPLE_N, straddles, straddleSampleGrid, minContrastOver, pickColorOver, STRADDLE_COLS, STRADDLE_ROWS, STRADDLE_MIN_SHARE, STRADDLE_TARGET_CONTRAST, STRADDLE_PILL_ALPHA, type LabelDecision, } from "./labelContrast";
27
27
  export { censusMarks, isBlankRender, blankRenderFlag, type MarkCensus, type BlankVerdictInput } from "./blankRender";
28
28
  export { isInvalidSentinelError, invalidSentinelReason } from "./invalidSentinel";
29
29
  export { censusHitBands, hitBandFlag, MIN_HIT_BAND_PX, type HitBandCensus } from "./hitBands";
@@ -53,4 +53,41 @@ export declare function glyphSampleGrid(box: {
53
53
  x: number;
54
54
  y: number;
55
55
  }[];
56
+ export declare const STRADDLE_COLS = 8;
57
+ export declare const STRADDLE_ROWS = 2;
58
+ /** The share of a label's samples a second surface must hold before the label straddles it. */
59
+ export declare const STRADDLE_MIN_SHARE = 0.125;
60
+ /** What a pill-backed label is held to over its whole box - WCAG AA for body text. */
61
+ export declare const STRADDLE_TARGET_CONTRAST = 4.5;
62
+ /** The pill's opacity: the boosted-pill value, so every backdrop this pass paints reads alike. */
63
+ export declare const STRADDLE_PILL_ALPHA = 0.9;
64
+ /** Sample points for the straddle test: STRADDLE_COLS x STRADDLE_ROWS cell centres over the box. */
65
+ export declare function straddleSampleGrid(box: {
66
+ left: number;
67
+ top: number;
68
+ width: number;
69
+ height: number;
70
+ }): {
71
+ x: number;
72
+ y: number;
73
+ }[];
74
+ /** Distinct surfaces among per-sample backgrounds (per-channel tolerance), largest first. */
75
+ export declare function backgroundGroups(bgs: [number, number, number][], tol?: number): {
76
+ rgb: [number, number, number];
77
+ n: number;
78
+ }[];
79
+ /** True when at least two surfaces each hold STRADDLE_MIN_SHARE of a label's samples. */
80
+ export declare function straddles(bgs: [number, number, number][]): boolean;
81
+ /** The lowest contrast a text colour reaches over every sample background (0 when unparseable). */
82
+ export declare function minContrastOver(textColor: string | null | undefined, bgs: [number, number, number][]): number;
83
+ /**
84
+ * The one colour for a label over several backgrounds: the author's own when it reaches `target`
85
+ * over all of them (a colour that reads is never overruled), else whichever of DARK_TEXT and
86
+ * LIGHT_TEXT reads best over the worst of them.
87
+ */
88
+ export declare function pickColorOver(textColor: string | null | undefined, bgs: [number, number, number][], target?: number): {
89
+ color: string;
90
+ contrast: number;
91
+ keep: boolean;
92
+ };
56
93
  export {};
@@ -30,7 +30,17 @@ export interface LabelContrastReport {
30
30
  /** Labels with a painting shape over their box that was set aside because it is drawn ON TOP
31
31
  * of them - an occluder, never a background. See drawnBeneath. */
32
32
  paintedOver: number;
33
+ /** Labels straddling a fill edge that got a page-coloured pill of their own instead of a
34
+ * recolour - one colour cannot read on two surfaces with opposite needs. */
35
+ straddlePills: number;
36
+ /** Adopted pills grown to cover their label's whole box, so no glyph starts off the pill. */
37
+ pillsExtended: number;
38
+ /** Labels partly covered by a shape drawn after them in their own group, moved above it. */
39
+ raised: number;
33
40
  /** Why the pass did nothing, when it did nothing. */
34
41
  skipped?: "no-container" | "no-shapes" | "too-many-shapes" | "too-many-texts" | "error";
35
42
  }
43
+ /** The class a pill this pass paints carries, so a reader of the DOM (or a test) can tell it from
44
+ * the chart's own shapes. */
45
+ export declare const LABEL_PILL_CLASS = "lch-label-pill";
36
46
  export declare function applyLabelContrast(container: HTMLElement | null | undefined, opts?: LabelContrastOptions): LabelContrastReport;
@@ -49,6 +49,17 @@ export declare const OPTIONS_VOCABULARY: Readonly<{
49
49
  /** "" chooses by the number of periods. */
50
50
  animTimelineStyle: OptionVocabularyEntry;
51
51
  filtersDuringPlay: OptionVocabularyEntry;
52
+ /** Where a card deck's flip controls live: every card's own arrows, one strip for the deck, or both. */
53
+ flipMode: OptionVocabularyEntry;
54
+ /**
55
+ * BLANK - "the chart's own" - is the default, and it is not 0. A host that was never told a value
56
+ * sends none (resolveOptions keeps it absent) and the chart supplies its own: manual on the card
57
+ * deck, a 5 s dwell on a carousel. 0 is a reader's explicit "manual only". A non-zero value is
58
+ * clamped chart-side to FLIP_INTERVAL_MIN_MS..FLIP_INTERVAL_MAX_MS.
59
+ */
60
+ flipIntervalMs: OptionVocabularyEntry;
61
+ /** Which way a face turns, for any chart that turns between faces: side to side, or top to bottom. */
62
+ flipDirection: OptionVocabularyEntry;
52
63
  levelOfDetail: OptionVocabularyEntry;
53
64
  favorLimitTo: OptionVocabularyEntry;
54
65
  /** 0 asks for no limit, and travels as absent (`wireLimitCount`): any value the server receives is a limit. */
@@ -1,5 +1,27 @@
1
1
  /**
2
- * The comparison form of a term or a field.
2
+ * HOW A TERM MATCHES A NAME - a reader's setting on every host, and "loose" unless they choose
3
+ * otherwise.
4
+ *
5
+ * "loose" - the rule for every match against names we know: diacritic-neutral and case-,
6
+ * whitespace- and punctuation-insensitive. "barchart", "bar-chart" and "Bar Chart" all
7
+ * find `Bar chart`. The exact form is still asked first, so a row the exact form found at
8
+ * a word start is found there still; the loose form only adds candidates. One consequence
9
+ * to know: an added word-start hit takes the answer to the name tier, which hides
10
+ * mid-word hits exactly as any word-start hit always has.
11
+ * "exact" - accents and case folded and runs of whitespace collapsed, and nothing else: "bar chart"
12
+ * and "bar chart" are the same query, but "barchart" and "bar-chart" are not. For a reader
13
+ * who wants that: one who omits the space is asking for something we do not have a name
14
+ * for, and a filter that succeeds there anyway can make its failures harder to explain.
15
+ */
16
+ export type FilterMatchStyle = "loose" | "exact";
17
+ /** The style a host uses when the reader has not chosen one. */
18
+ export declare const DEFAULT_FILTER_MATCH_STYLE: FilterMatchStyle;
19
+ /** Read a host's stored setting: "exact" only when it says exactly that, "loose" otherwise - so a
20
+ * missing, empty or unrecognised value is the default, never an error. */
21
+ export declare function filterMatchStyleOf(raw: unknown): FilterMatchStyle;
22
+ /**
23
+ * The comparison form of a term or a field - the EXACT form, which every style asks first and
24
+ * which hosts show back to the reader (the `term` of a result).
3
25
  *
4
26
  * Accent folding is not decoration. The catalogue is English, but the reader's keyboard need not
5
27
  * be, and a "Sankey" typed through a dead key has to match the same row a plain one does. NFD
@@ -8,8 +30,8 @@
8
30
  * different chart names collide.
9
31
  *
10
32
  * Whitespace is collapsed rather than stripped: "bar chart" and "bar chart" are the same query,
11
- * but "barchart" is deliberately NOT one. A reader who omits the space is asking for something we
12
- * do not have a name for, and silently succeeding there would make the failures inexplicable.
33
+ * and "barchart" is not the same FORM. Whether "barchart" still FINDS `Bar chart` is the match
34
+ * style's business (see FilterMatchStyle): under "loose" it does, through the loose form.
13
35
  */
14
36
  export declare function normalizeFilterTerm(raw: string | null | undefined): string;
15
37
  /**
@@ -65,8 +87,14 @@ export type QualifyFilterRead<T> = (row: T) => {
65
87
  *
66
88
  * A row with no name is dropped from every tier. It cannot be labelled, so it cannot be chosen,
67
89
  * and the hosts already drop it at render time.
90
+ *
91
+ * UNDER THE LOOSE STYLE (the default) each field is asked in its exact form first and its loose
92
+ * form only when the exact form does not contain the term, and a loose hit counts only where it
93
+ * starts a word: "barchart" starts a word in `Bar chart` and `Stacked bar chart`, so it answers in
94
+ * the name tier, while "terna" is not found inside "patTERN Across". The `term` returned is always
95
+ * the exact form - it is what a host shows back to the reader.
68
96
  */
69
- export declare function filterQualifyRows<T>(rows: readonly T[] | null | undefined, term: string | null | undefined, read: QualifyFilterRead<T>): QualifyFilterResult<T>;
97
+ export declare function filterQualifyRows<T>(rows: readonly T[] | null | undefined, term: string | null | undefined, read: QualifyFilterRead<T>, style?: FilterMatchStyle): QualifyFilterResult<T>;
70
98
  /** Reads a fitting row (`charts[]`): `name` / `description`.
71
99
  *
72
100
  * GENERIC, and it has to be. Written as a `const` with an explicit `QualifyFilterRead<{...}>`
@@ -274,7 +302,7 @@ export interface QualifyFilterView<E> {
274
302
  * ORDER IS UNTOUCHED, as everywhere else here - `show` and `hide` come out in the order the
275
303
  * groups were built, so a host writing them in sequence cannot reorder anything by accident.
276
304
  */
277
- export declare function computeQualifyFilterView<E>(groups: readonly QualifyFilterGroup<E>[], term: string | null | undefined): QualifyFilterView<E>;
305
+ export declare function computeQualifyFilterView<E>(groups: readonly QualifyFilterGroup<E>[], term: string | null | undefined, style?: FilterMatchStyle): QualifyFilterView<E>;
278
306
  /**
279
307
  * The counter beside the box: "12 of 137" while filtering, the plain total otherwise - and
280
308
  * "0 of 19 (+1)" when the term also reached the refusal block.
@@ -11,9 +11,45 @@ export interface SnapshotOptions {
11
11
  }
12
12
  /**
13
13
  * Serialize an SVG element to a `data:image/svg+xml;base64,` URL, with intrinsic
14
- * width/height inlined on a clone so a later Image() load knows its size.
14
+ * width/height inlined on a clone so a later Image() load knows its size, and the computed font
15
+ * of its text inlined so the picture is not drawn in a default serif.
15
16
  */
16
17
  export declare function svgToDataUrl(svg: SVGSVGElement): string;
18
+ /**
19
+ * THE TABLE HOST a snapshot of `root` should capture, or null when the chart's picture is an SVG.
20
+ *
21
+ * A table lane draws HTML rows with a small <svg> in each cell, so its first <svg> is one cell.
22
+ * The host is the `.lch-table-frame` the table helper builds, else a <table> - and only when the
23
+ * first <svg> under `root` sits INSIDE it (or there is no svg at all): a chart whose first svg is
24
+ * outside any table is an SVG chart with a table beside it, and keeps its SVG snapshot.
25
+ *
26
+ * Exported because the same question decides what a host measures to fit a chart to its frame: on a
27
+ * table lane that is the frame, never a cell.
28
+ */
29
+ export declare function tableHostOf(root: Element | null | undefined): HTMLElement | null;
30
+ /**
31
+ * THE CHART'S OWN <svg> under `root`: the one stamped SNAPSHOT_SVG_ATTR, else the first.
32
+ *
33
+ * ONE PICKER for everything that acts on "the chart's svg" - the thumbnail here and the frame grow in
34
+ * fitDom - because a chart with several svgs (a carousel mounts its front face between two peeks) is
35
+ * otherwise read by whichever was appended first, and the two callers would each have to know that.
36
+ */
37
+ export declare function chartSvgOf(root: Element | null | undefined): SVGSVGElement | null;
38
+ /** The drawn size of an HTML element, with an inline-style and then a fixed fallback. */
39
+ export declare function htmlNaturalSize(el: HTMLElement): {
40
+ width: number;
41
+ height: number;
42
+ };
43
+ /**
44
+ * Serialize an HTML element - a table lane's frame - to an SVG data URL: a clone with its computed
45
+ * styles inlined, inside a <foreignObject> the size of the element. The picture is what the reader
46
+ * saw: the frame's own box, from the top of its scroll.
47
+ */
48
+ export declare function htmlToSvgDataUrl(el: HTMLElement): {
49
+ url: string;
50
+ width: number;
51
+ height: number;
52
+ };
17
53
  /** The measured drawing size of an SVG, with the same fallbacks svgToDataUrl inlines. */
18
54
  export declare function svgNaturalSize(svg: SVGSVGElement): {
19
55
  width: number;
@@ -25,8 +61,12 @@ export declare function svgNaturalSize(svg: SVGSVGElement): {
25
61
  */
26
62
  export declare function rasterizeSvgToPngDataUrl(svgDataUrl: string, width: number, height: number, opts?: SnapshotOptions): Promise<string | null>;
27
63
  /**
28
- * Capture the first <svg> under `root` (or the element itself) as a PNG data URL, falling
29
- * back to the SVG data URL when rasterizing is unavailable, and to null only when there is
30
- * genuinely nothing on the canvas to capture.
64
+ * Capture the chart under `root` as a PNG data URL: its table FRAME when the chart is an HTML table
65
+ * lane (see tableHostOf), else the chart's own <svg> under `root` (chartSvgOf), or the element itself. Falls back to
66
+ * the SVG data URL when rasterizing is unavailable, and to null only when there is genuinely nothing
67
+ * on the canvas to capture.
68
+ *
69
+ * PASS THE CONTAINER, not an svg found beforehand: only the container lets this tell a table lane
70
+ * from an SVG chart.
31
71
  */
32
72
  export declare function captureSvgSnapshot(root: Element | null | undefined, opts?: SnapshotOptions): Promise<string | null>;
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "@bicharts/chart-host",
3
- "version": "0.6.47",
3
+ "version": "0.6.49",
4
4
  "description": "Run a BIC-generated D3 chart in any web host: compiles the generated render() function, applies the shared option defaults, resolves mark clicks (through tooltip overlays), owns the selection affordance, and translates row indices between cross-filtered charts. The same contract the BIC Power BI visual implements, minus Power BI. React bindings at @bicharts/chart-host/react.",
5
5
  "license": "Apache-2.0",
6
6
  "type": "module",