@bicharts/chart-host 0.5.41 → 0.5.43
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.mjs +47 -0
- package/dist/types/index.d.ts +1 -0
- package/dist/types/qualifyLaunch.d.ts +136 -0
- package/package.json +1 -1
package/dist/index.mjs
CHANGED
|
@@ -574,6 +574,40 @@ function qualifyGroupHeadingFor(row, state) {
|
|
|
574
574
|
return null;
|
|
575
575
|
}
|
|
576
576
|
|
|
577
|
+
// src/qualifyLaunch.ts
|
|
578
|
+
var qualifyPick = (chartType) => ({ kind: "pick", chartType });
|
|
579
|
+
var qualifyAuto = () => ({ kind: "auto" });
|
|
580
|
+
var qualifyCancel = () => ({ kind: "cancel" });
|
|
581
|
+
function launchGenerates(outcome) {
|
|
582
|
+
return outcome.kind === "pick" || outcome.kind === "auto";
|
|
583
|
+
}
|
|
584
|
+
function launchFavorStyle(outcome, autoSentinel) {
|
|
585
|
+
return outcome.kind === "pick" ? outcome.chartType : autoSentinel;
|
|
586
|
+
}
|
|
587
|
+
var CHOOSER_MIN_WIDTH_PX = 400;
|
|
588
|
+
var CHOOSER_MIN_HEIGHT_PX = 240;
|
|
589
|
+
function chooserFitsViewport(width, height) {
|
|
590
|
+
if (!isFinite(width) || !isFinite(height)) return false;
|
|
591
|
+
return width >= CHOOSER_MIN_WIDTH_PX && height >= CHOOSER_MIN_HEIGHT_PX;
|
|
592
|
+
}
|
|
593
|
+
function shouldOpenChooserOnGenerate(i) {
|
|
594
|
+
if (!i.enabled) return false;
|
|
595
|
+
if (!i.hasData) return false;
|
|
596
|
+
return chooserFitsViewport(i.width, i.height);
|
|
597
|
+
}
|
|
598
|
+
function shouldOpenInlineChooserOnGenerate(i) {
|
|
599
|
+
return i.enabled === true && i.hasData === true;
|
|
600
|
+
}
|
|
601
|
+
function canConfirmLaunch(selected) {
|
|
602
|
+
return typeof selected === "string" && selected.trim() !== "";
|
|
603
|
+
}
|
|
604
|
+
function confirmLaunch(selected) {
|
|
605
|
+
return canConfirmLaunch(selected) ? qualifyPick(String(selected).trim()) : qualifyCancel();
|
|
606
|
+
}
|
|
607
|
+
function qualifyFailureFallsOpen(viaGenerate) {
|
|
608
|
+
return viaGenerate === true;
|
|
609
|
+
}
|
|
610
|
+
|
|
577
611
|
// src/selectionCard.ts
|
|
578
612
|
var SYNTHETIC_PREFIX = "__";
|
|
579
613
|
var NUMERIC_DATATYPE = /int|double|decimal|single|float|number|currency|money/i;
|
|
@@ -753,6 +787,8 @@ export {
|
|
|
753
787
|
ANIM_PLAY_SPEED_MAX,
|
|
754
788
|
ANIM_PLAY_SPEED_MIN,
|
|
755
789
|
AXIS_FILTER_CLASS,
|
|
790
|
+
CHOOSER_MIN_HEIGHT_PX,
|
|
791
|
+
CHOOSER_MIN_WIDTH_PX,
|
|
756
792
|
COLOR_SCALE_SELF_CLAMP_PCT_DEFAULT,
|
|
757
793
|
COLOR_SCALE_SELF_CLAMP_PCT_MAX,
|
|
758
794
|
COLOR_SCALE_SELF_CLAMP_PCT_MIN,
|
|
@@ -777,30 +813,41 @@ export {
|
|
|
777
813
|
bareBase64,
|
|
778
814
|
buildRenderPayload,
|
|
779
815
|
buildReviewWire,
|
|
816
|
+
canConfirmLaunch,
|
|
780
817
|
captureSvgSnapshot,
|
|
781
818
|
chartOwnsTimeline,
|
|
819
|
+
chooserFitsViewport,
|
|
782
820
|
clearGeoCache,
|
|
783
821
|
compileRenderFn,
|
|
784
822
|
compileTrivialSource,
|
|
785
823
|
computeSelectionCard,
|
|
824
|
+
confirmLaunch,
|
|
786
825
|
createChartHost,
|
|
787
826
|
createMarkResolver,
|
|
788
827
|
ensureCrossfilterHitTargets,
|
|
789
828
|
explainRenderFailure,
|
|
790
829
|
geoAssetFor,
|
|
791
830
|
geoFromCache,
|
|
831
|
+
launchFavorStyle,
|
|
832
|
+
launchGenerates,
|
|
792
833
|
loadGeo,
|
|
793
834
|
newQualifyGroupState,
|
|
794
835
|
normaliseAggregation,
|
|
795
836
|
periodTickSuppressesFeedback,
|
|
796
837
|
planTrivialChart,
|
|
838
|
+
qualifyAuto,
|
|
839
|
+
qualifyCancel,
|
|
840
|
+
qualifyFailureFallsOpen,
|
|
797
841
|
qualifyGroupHeadingFor,
|
|
842
|
+
qualifyPick,
|
|
798
843
|
rasterizeSvgToPngDataUrl,
|
|
799
844
|
registerCityTable,
|
|
800
845
|
registerGeo,
|
|
801
846
|
registerGeoAsset,
|
|
802
847
|
requiredD3Plugins,
|
|
803
848
|
resolveOptions,
|
|
849
|
+
shouldOpenChooserOnGenerate,
|
|
850
|
+
shouldOpenInlineChooserOnGenerate,
|
|
804
851
|
shouldReview,
|
|
805
852
|
stripEsmExports,
|
|
806
853
|
svgNaturalSize,
|
package/dist/types/index.d.ts
CHANGED
|
@@ -12,5 +12,6 @@ export { captureSvgSnapshot, svgToDataUrl, svgNaturalSize, rasterizeSvgToPngData
|
|
|
12
12
|
export { shouldReview, buildReviewWire, bareBase64, actionFor, type ReviewGate, type ReviewWire, type ReviewVerdict, type ReviewAction } from "./review";
|
|
13
13
|
export { askApplyImprovements, type ReviewDialogOptions, type ReviewDialogText } from "./reviewDialog";
|
|
14
14
|
export { qualifyGroupHeadingFor, newQualifyGroupState, type QualifyGroupRow, type QualifyGroupState, type QualifyGroupHeading, } from "./qualifyGroups";
|
|
15
|
+
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";
|
|
15
16
|
export { computeSelectionCard, normaliseAggregation, type SelectionCardModel, type SelectionCardLine, type SelectionCardOptions, } from "./selectionCard";
|
|
16
17
|
export { ensureCrossfilterHitTargets, type HitTargetReport } from "./hitTargets";
|
|
@@ -0,0 +1,136 @@
|
|
|
1
|
+
/** How the reader left the chooser. Three outcomes, never two - see the note above. */
|
|
2
|
+
export type QualifyLaunchOutcome =
|
|
3
|
+
/** A named type. Rides the host's explicit-pick lane for exactly one generation. */
|
|
4
|
+
{
|
|
5
|
+
kind: "pick";
|
|
6
|
+
chartType: string;
|
|
7
|
+
}
|
|
8
|
+
/** "Choose for me." Generates with NO preference expressed. */
|
|
9
|
+
| {
|
|
10
|
+
kind: "auto";
|
|
11
|
+
}
|
|
12
|
+
/** Backed out. Nothing is generated and no preference is recorded. */
|
|
13
|
+
| {
|
|
14
|
+
kind: "cancel";
|
|
15
|
+
};
|
|
16
|
+
export declare const qualifyPick: (chartType: string) => QualifyLaunchOutcome;
|
|
17
|
+
export declare const qualifyAuto: () => QualifyLaunchOutcome;
|
|
18
|
+
export declare const qualifyCancel: () => QualifyLaunchOutcome;
|
|
19
|
+
/** Does this outcome start a generation? False for cancel ALONE. */
|
|
20
|
+
export declare function launchGenerates(outcome: QualifyLaunchOutcome): boolean;
|
|
21
|
+
/**
|
|
22
|
+
* The value a host should put in its explicit-pick field for this outcome.
|
|
23
|
+
*
|
|
24
|
+
* GENERIC OVER THE SENTINEL BECAUSE THE HOSTS DISAGREE ABOUT WHAT "AUTO" IS SPELLED AS, and
|
|
25
|
+
* that disagreement is real rather than sloppy: one host's field is a nullable string whose
|
|
26
|
+
* null means "the picker decides", another's is a plain string whose empty value is the wire
|
|
27
|
+
* form. Neither can adopt the other's without changing a wire contract. So the sentinel is
|
|
28
|
+
* passed IN and this function only decides WHICH of the two values applies - which is the part
|
|
29
|
+
* that must not differ.
|
|
30
|
+
*
|
|
31
|
+
* Cancel maps to the sentinel too, defensively: a caller that ignores `launchGenerates` and
|
|
32
|
+
* reads this anyway gets "no preference" rather than a stale pick. It should still not generate.
|
|
33
|
+
*/
|
|
34
|
+
export declare function launchFavorStyle<T>(outcome: QualifyLaunchOutcome, autoSentinel: T): string | T;
|
|
35
|
+
/**
|
|
36
|
+
* THE SMALLEST TILE THE CHOOSER IS USABLE IN, measured rather than guessed (2026-09-01).
|
|
37
|
+
*
|
|
38
|
+
* A sweep of 168 tile sizes in headless Chromium, rendering the real card DOM and CSS, asking
|
|
39
|
+
* three questions of each: do the three launch buttons sit on one line inside the card, are at
|
|
40
|
+
* least two list rows visible, and is nothing in the pinned chrome clipped. The measured floor
|
|
41
|
+
* is 320 x 220 - but the two dimensions are COUPLED, because under 400 px the card's title
|
|
42
|
+
* wraps to a second line and eats the list's height: at 320-340 wide the height floor rises to
|
|
43
|
+
* 280, at 360-380 to 260, and only at 400+ does 220 hold.
|
|
44
|
+
*
|
|
45
|
+
* 400 x 240 is that envelope with one sweep step of margin on the height. The margin is not
|
|
46
|
+
* decoration: the measurement used one font stack and one string, and every host localizes the
|
|
47
|
+
* title, so a longer translation wraps sooner than the sample did.
|
|
48
|
+
*
|
|
49
|
+
* ERRING HIGH IS THE CHEAP DIRECTION. Below the floor the host generates immediately, which is
|
|
50
|
+
* the behaviour it had before the chooser existed - so a tile wrongly judged too small costs a
|
|
51
|
+
* feature, while one wrongly judged big enough costs a dialog whose buttons are off the card.
|
|
52
|
+
*/
|
|
53
|
+
export declare const CHOOSER_MIN_WIDTH_PX = 400;
|
|
54
|
+
export declare const CHOOSER_MIN_HEIGHT_PX = 240;
|
|
55
|
+
/**
|
|
56
|
+
* Is there room to DRAW the chooser here?
|
|
57
|
+
*
|
|
58
|
+
* MEASURE THE REAL SURFACE, never a size the host reports outward. Where a host lets an author
|
|
59
|
+
* state a viewport for generation purposes, that stated size is a claim about a tile that does
|
|
60
|
+
* not exist yet; the dialog has to fit the pixels actually on screen.
|
|
61
|
+
*/
|
|
62
|
+
export declare function chooserFitsViewport(width: number, height: number): boolean;
|
|
63
|
+
export interface ChooserGateInput {
|
|
64
|
+
/** The host's opt-out setting. False = the reader wants one-click Generate back. */
|
|
65
|
+
enabled: boolean;
|
|
66
|
+
/** Real drawable width, in CSS pixels. */
|
|
67
|
+
width: number;
|
|
68
|
+
/** Real drawable height, in CSS pixels. */
|
|
69
|
+
height: number;
|
|
70
|
+
/**
|
|
71
|
+
* Is there anything to qualify? A chooser over an empty binding can only say "bind
|
|
72
|
+
* something first", which the host's own Generate path already says better and without
|
|
73
|
+
* a round-trip.
|
|
74
|
+
*/
|
|
75
|
+
hasData: boolean;
|
|
76
|
+
}
|
|
77
|
+
/**
|
|
78
|
+
* Should pressing Generate open the chooser instead of generating?
|
|
79
|
+
*
|
|
80
|
+
* FALSE IS ALWAYS SAFE and that is the design: every false answer here lands on the behaviour
|
|
81
|
+
* the host had before this feature existed - press Generate, get a chart. So the gate can be
|
|
82
|
+
* conservative without stranding anybody, and a new reason to decline can be added later
|
|
83
|
+
* without auditing what it breaks.
|
|
84
|
+
*/
|
|
85
|
+
export declare function shouldOpenChooserOnGenerate(i: ChooserGateInput): boolean;
|
|
86
|
+
/**
|
|
87
|
+
* The same gate for a host whose chooser is an INLINE, SCROLLING PANEL rather than a modal card
|
|
88
|
+
* - and it deliberately has no size clause at all.
|
|
89
|
+
*
|
|
90
|
+
* THE ASYMMETRY IS THE POINT, AND IT IS MEASURED RATHER THAN ASSUMED. The modal above lives in
|
|
91
|
+
* a card that CLIPS, so past a certain smallness its buttons are simply not on screen and the
|
|
92
|
+
* reader is trapped. A panel that flows inside a scrolling pane, with a wrapping button row,
|
|
93
|
+
* cannot reach that state: swept across 63 pane sizes down to 200x120, every one stayed usable
|
|
94
|
+
* - the footer wrapped from one line to three (38px to 86px) and stayed inside the panel, and
|
|
95
|
+
* the list kept four or more rows because it carries its own max-height and scrolls.
|
|
96
|
+
*
|
|
97
|
+
* So a size clause here would not protect anybody; it would only switch the feature off for a
|
|
98
|
+
* default task pane, which is narrower than the modal's floor. Two hosts, two layouts, two
|
|
99
|
+
* honest answers - written next to each other so the difference reads as a decision rather than
|
|
100
|
+
* as one of them having forgotten.
|
|
101
|
+
*/
|
|
102
|
+
export declare function shouldOpenInlineChooserOnGenerate(i: {
|
|
103
|
+
enabled: boolean;
|
|
104
|
+
hasData: boolean;
|
|
105
|
+
}): boolean;
|
|
106
|
+
/**
|
|
107
|
+
* Is the confirm button live?
|
|
108
|
+
*
|
|
109
|
+
* A SEPARATE QUESTION FROM "is a type selected", because it is the answer to a UI state and the
|
|
110
|
+
* host asks it on every selection change. Kept here so both hosts agree that selecting a row is
|
|
111
|
+
* what arms confirm - the alternative, arming it always and validating on click, produces a
|
|
112
|
+
* button that looks ready and then refuses, which is the interaction this flow replaced.
|
|
113
|
+
*/
|
|
114
|
+
export declare function canConfirmLaunch(selected: string | null | undefined): boolean;
|
|
115
|
+
/**
|
|
116
|
+
* The outcome of pressing confirm with `selected` highlighted.
|
|
117
|
+
*
|
|
118
|
+
* Returns CANCEL rather than auto when nothing is selected, and the choice matters: confirm
|
|
119
|
+
* with an empty selection is a state the UI should not allow, so if it happens the honest
|
|
120
|
+
* reading is "this click means nothing", not "this click means spend a credit". The host's
|
|
121
|
+
* disabled state is the first guard; this is the second.
|
|
122
|
+
*/
|
|
123
|
+
export declare function confirmLaunch(selected: string | null | undefined): QualifyLaunchOutcome;
|
|
124
|
+
/**
|
|
125
|
+
* WHAT A FAILED QUALIFY MEANS depends on which door the reader came through, and this is the
|
|
126
|
+
* one place that says so.
|
|
127
|
+
*
|
|
128
|
+
* Opened from Generate, the reader asked for a CHART: the chooser is an offer along the way, so
|
|
129
|
+
* when qualify errors or times out the flow proceeds to generate and the degradation is logged
|
|
130
|
+
* rather than shown. Opened from a "what fits?" affordance, the reader asked a QUESTION: failing
|
|
131
|
+
* open there would spend a credit nobody requested, so the error is shown and nothing runs.
|
|
132
|
+
*
|
|
133
|
+
* This is the whole reason the two doors are distinguishable at all. Everything else about them
|
|
134
|
+
* - the list, the buttons, the outcomes - is deliberately identical.
|
|
135
|
+
*/
|
|
136
|
+
export declare function qualifyFailureFallsOpen(viaGenerate: boolean): boolean;
|
package/package.json
CHANGED
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
{
|
|
2
2
|
"name": "@bicharts/chart-host",
|
|
3
|
-
"version": "0.5.
|
|
3
|
+
"version": "0.5.43",
|
|
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",
|