@silverpoint/core 0.1.1 → 0.2.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/dashboard-demos.d.ts +103 -0
- package/dist/dashboard-demos.js +94 -0
- package/dist/dashboard-demos.js.map +1 -0
- package/dist/index.d.ts +92 -485
- package/dist/index.js +253 -7
- package/dist/index.js.map +1 -1
- package/dist/types-D1hjElfL.d.ts +719 -0
- package/package.json +7 -1
package/dist/index.js
CHANGED
|
@@ -244,6 +244,21 @@ var WARNINGS = {
|
|
|
244
244
|
what: "the path byte budget of 40 KB is exceeded",
|
|
245
245
|
todo: "Use `hatchFill: 'tile'` or a larger hatch gap"
|
|
246
246
|
},
|
|
247
|
+
SP014: {
|
|
248
|
+
req: "REQ-204",
|
|
249
|
+
what: "a dashboard cell spans more columns than the breakpoint has; it is clamped",
|
|
250
|
+
todo: "Lower the span, or give that breakpoint more columns"
|
|
251
|
+
},
|
|
252
|
+
SP015: {
|
|
253
|
+
req: "REQ-205",
|
|
254
|
+
what: "the dashboard layout and its children disagree; unmatched children are placed in source order, span 1",
|
|
255
|
+
todo: "Give every child a `cell` the layout declares, once"
|
|
256
|
+
},
|
|
257
|
+
SP016: {
|
|
258
|
+
req: "REQ-217",
|
|
259
|
+
what: "a chart in a linked dashboard has no field named by `link.key`; it shows no linked mark",
|
|
260
|
+
todo: "Link on a field every linked chart carries, or leave this chart out of the link"
|
|
261
|
+
},
|
|
247
262
|
SP013: {
|
|
248
263
|
req: "REQ-032",
|
|
249
264
|
what: "the @silverpoint/fonts face failed to load; rendering fell back to the system stack",
|
|
@@ -285,6 +300,7 @@ function pathView(stroke) {
|
|
|
285
300
|
role: stroke.role,
|
|
286
301
|
paint,
|
|
287
302
|
dash: stroke.dash ?? null,
|
|
303
|
+
weight: stroke.tonalWeight === void 0 ? null : String(stroke.tonalWeight),
|
|
288
304
|
fill: paint === "tile" && stroke.tile ? `url(#${stroke.tile})` : null
|
|
289
305
|
};
|
|
290
306
|
}
|
|
@@ -336,6 +352,7 @@ function pathString(path) {
|
|
|
336
352
|
["data-role", path.role],
|
|
337
353
|
["data-paint", path.paint],
|
|
338
354
|
["data-dash", path.dash],
|
|
355
|
+
["data-weight", path.weight],
|
|
339
356
|
["fill", path.fill]
|
|
340
357
|
])}></path>`;
|
|
341
358
|
}
|
|
@@ -4204,7 +4221,6 @@ function fits(frame, name, at2, inner, outer, start, end) {
|
|
|
4204
4221
|
});
|
|
4205
4222
|
}
|
|
4206
4223
|
function buildVolvelleChart(props, context) {
|
|
4207
|
-
const usesDemo = props.data === void 0;
|
|
4208
4224
|
const all = props.data ?? VOLVELLE_CHART_DEMO;
|
|
4209
4225
|
const { locale } = context;
|
|
4210
4226
|
const cap = props.rings !== void 0 && Number.isInteger(props.rings) && props.rings > 0 ? props.rings : all.length;
|
|
@@ -4218,16 +4234,13 @@ function buildVolvelleChart(props, context) {
|
|
|
4218
4234
|
checkSectors(CHART23, "segments", segments.length);
|
|
4219
4235
|
rings.push({ label: formatCategory(datum.label, locale), segments: segments.map((s) => formatCategory(s, locale)), given: index });
|
|
4220
4236
|
});
|
|
4221
|
-
|
|
4222
|
-
warnValue(CHART23, props.indexValue !== void 0 ? "indexValue" : "indexRing", "Without `data` the demo keeps its own index; `indexRing` and `indexValue` apply to your rings.");
|
|
4223
|
-
}
|
|
4224
|
-
let ringIndex = usesDemo || props.indexRing === void 0 ? 0 : rings.findIndex((r) => r.given === props.indexRing);
|
|
4237
|
+
let ringIndex = props.indexRing === void 0 ? 0 : rings.findIndex((r) => r.given === props.indexRing);
|
|
4225
4238
|
if (ringIndex < 0) {
|
|
4226
4239
|
if (rings.length > 0) warnValue(CHART23, "indexRing", `Ring ${String(props.indexRing)} does not exist or has no segments; the index reads the first ring.`);
|
|
4227
4240
|
ringIndex = 0;
|
|
4228
4241
|
}
|
|
4229
4242
|
const turned = rings[ringIndex];
|
|
4230
|
-
let segment = turned &&
|
|
4243
|
+
let segment = turned && props.indexValue !== void 0 ? turned.segments.indexOf(props.indexValue) : 0;
|
|
4231
4244
|
if (segment < 0) {
|
|
4232
4245
|
warnValue(CHART23, "indexValue", `"${String(props.indexValue)}" is not on ring "${turned?.label}"; the index reads its first segment.`);
|
|
4233
4246
|
segment = 0;
|
|
@@ -4765,6 +4778,239 @@ var bubbleChart = /* @__PURE__ */ Object.freeze({
|
|
|
4765
4778
|
build: (props, context) => buildPoints(FAMILY6, props, context, BUBBLE_CHART_DEMO)
|
|
4766
4779
|
});
|
|
4767
4780
|
|
|
4768
|
-
|
|
4781
|
+
// src/dashboard/defaults.ts
|
|
4782
|
+
var BREAKPOINTS = ["sm", "md", "lg"];
|
|
4783
|
+
var DASHBOARD = "Dashboard";
|
|
4784
|
+
var MAX_COLUMNS = 12;
|
|
4785
|
+
var MAX_ROW_SPAN = 6;
|
|
4786
|
+
var DASHBOARD_DEFAULTS = /* @__PURE__ */ Object.freeze({
|
|
4787
|
+
columns: /* @__PURE__ */ Object.freeze({ sm: 1, md: 2, lg: 4 }),
|
|
4788
|
+
rowHeight: 240,
|
|
4789
|
+
gap: 16,
|
|
4790
|
+
span: 1,
|
|
4791
|
+
headingLevel: 2,
|
|
4792
|
+
ssrWidth: 1200
|
|
4793
|
+
});
|
|
4794
|
+
function perBreakpoint(value, fallback) {
|
|
4795
|
+
const given = value !== null && typeof value === "object" ? value : void 0;
|
|
4796
|
+
const bare = value !== void 0 && given === void 0 ? value : void 0;
|
|
4797
|
+
return Object.fromEntries(BREAKPOINTS.map((bp) => [bp, bare ?? given?.[bp] ?? fallback[bp]]));
|
|
4798
|
+
}
|
|
4799
|
+
function corrected(property, given, used, rule) {
|
|
4800
|
+
if (process.env.NODE_ENV !== "production") {
|
|
4801
|
+
diagnose("SP002", DASHBOARD, { property, message: `${String(given)} is not ${rule}; ${used} is used.` });
|
|
4802
|
+
}
|
|
4803
|
+
return used;
|
|
4804
|
+
}
|
|
4805
|
+
var isInteger = (n) => typeof n === "number" && Number.isInteger(n);
|
|
4806
|
+
function resolveLayout(layout) {
|
|
4807
|
+
const asked = perBreakpoint(layout?.columns, DASHBOARD_DEFAULTS.columns);
|
|
4808
|
+
const columns = Object.fromEntries(
|
|
4809
|
+
BREAKPOINTS.map((bp) => {
|
|
4810
|
+
const n = asked[bp];
|
|
4811
|
+
const ok = isInteger(n) && n >= 1 && n <= MAX_COLUMNS;
|
|
4812
|
+
return [bp, ok ? n : corrected(`columns.${bp}`, n, DASHBOARD_DEFAULTS.columns[bp], `an integer from 1 to ${MAX_COLUMNS}`)];
|
|
4813
|
+
})
|
|
4814
|
+
);
|
|
4815
|
+
const rowHeight = layout?.rowHeight;
|
|
4816
|
+
const gap = layout?.gap;
|
|
4817
|
+
const one = { sm: 1, md: 1, lg: 1 };
|
|
4818
|
+
return {
|
|
4819
|
+
columns,
|
|
4820
|
+
rowHeight: rowHeight === void 0 ? DASHBOARD_DEFAULTS.rowHeight : Number.isFinite(rowHeight) && rowHeight > 0 ? rowHeight : corrected("rowHeight", rowHeight, DASHBOARD_DEFAULTS.rowHeight, "a number above 0"),
|
|
4821
|
+
gap: gap === void 0 ? DASHBOARD_DEFAULTS.gap : Number.isFinite(gap) && gap >= 0 ? gap : corrected("gap", gap, DASHBOARD_DEFAULTS.gap, "a number of 0 or more"),
|
|
4822
|
+
cells: (layout?.cells ?? []).map((cell, index) => {
|
|
4823
|
+
const col = perBreakpoint(cell.colSpan, one);
|
|
4824
|
+
const row = perBreakpoint(cell.rowSpan, one);
|
|
4825
|
+
const where = `cells[${index}]`;
|
|
4826
|
+
const span = Object.fromEntries(
|
|
4827
|
+
BREAKPOINTS.map((bp) => {
|
|
4828
|
+
let c = col[bp];
|
|
4829
|
+
if (!isInteger(c) || c < 1) c = corrected(`${where}.colSpan.${bp}`, c, 1, "an integer of 1 or more");
|
|
4830
|
+
else if (c > columns[bp]) {
|
|
4831
|
+
if (process.env.NODE_ENV !== "production") {
|
|
4832
|
+
diagnose("SP014", DASHBOARD, { property: `${where}.colSpan.${bp}`, message: `Cell "${cell.id}" spans ${c} columns at ${bp}, which has ${columns[bp]}; it spans ${columns[bp]}.` });
|
|
4833
|
+
}
|
|
4834
|
+
c = columns[bp];
|
|
4835
|
+
}
|
|
4836
|
+
let r = row[bp];
|
|
4837
|
+
if (!isInteger(r)) r = corrected(`${where}.rowSpan.${bp}`, r, 1, `an integer from 1 to ${MAX_ROW_SPAN}`);
|
|
4838
|
+
else if (r < 1 || r > MAX_ROW_SPAN) r = corrected(`${where}.rowSpan.${bp}`, r, Math.min(Math.max(r, 1), MAX_ROW_SPAN), `an integer from 1 to ${MAX_ROW_SPAN}`);
|
|
4839
|
+
return [bp, { col: c, row: r }];
|
|
4840
|
+
})
|
|
4841
|
+
);
|
|
4842
|
+
return { id: cell.id, span };
|
|
4843
|
+
})
|
|
4844
|
+
};
|
|
4845
|
+
}
|
|
4846
|
+
|
|
4847
|
+
// src/dashboard/resolve.ts
|
|
4848
|
+
var UNSAFE = /[^A-Za-z0-9_.:-]+/g;
|
|
4849
|
+
var MD_FROM = 640;
|
|
4850
|
+
var LG_FROM = 1024;
|
|
4851
|
+
var PROBE = 100;
|
|
4852
|
+
function safeIdOf(id) {
|
|
4853
|
+
return id.replace(UNSAFE, "-");
|
|
4854
|
+
}
|
|
4855
|
+
function warn(code, property, message) {
|
|
4856
|
+
if (process.env.NODE_ENV !== "production") diagnose(code, DASHBOARD, { property, message });
|
|
4857
|
+
}
|
|
4858
|
+
function breakpointOf(width) {
|
|
4859
|
+
return width >= LG_FROM ? "lg" : width >= MD_FROM ? "md" : "sm";
|
|
4860
|
+
}
|
|
4861
|
+
function nominalBox(layout, span, width) {
|
|
4862
|
+
const bp = breakpointOf(width);
|
|
4863
|
+
const { col, row } = span[bp];
|
|
4864
|
+
const cols = layout.columns[bp];
|
|
4865
|
+
const { gap, rowHeight } = layout;
|
|
4866
|
+
return {
|
|
4867
|
+
width: round2((width - gap * (cols - 1)) / cols * col + gap * (col - 1)),
|
|
4868
|
+
height: round2(rowHeight * row + gap * (row - 1))
|
|
4869
|
+
};
|
|
4870
|
+
}
|
|
4871
|
+
function cellStyle(span) {
|
|
4872
|
+
const style = {};
|
|
4873
|
+
for (const bp of BREAKPOINTS) style[`--sp-cell-col-${bp}`] = String(span[bp].col);
|
|
4874
|
+
for (const bp of BREAKPOINTS) style[`--sp-cell-row-${bp}`] = String(span[bp].row);
|
|
4875
|
+
return style;
|
|
4876
|
+
}
|
|
4877
|
+
function resolveDashboard(props, childCells) {
|
|
4878
|
+
const layout = resolveLayout(props.layout);
|
|
4879
|
+
let ssrWidth = DASHBOARD_DEFAULTS.ssrWidth;
|
|
4880
|
+
if (props.ssrWidth !== void 0) {
|
|
4881
|
+
if (Number.isFinite(props.ssrWidth) && props.ssrWidth > 0) ssrWidth = props.ssrWidth;
|
|
4882
|
+
else warn("SP002", "ssrWidth", `${String(props.ssrWidth)} is not a width above 0; ${ssrWidth} is used.`);
|
|
4883
|
+
}
|
|
4884
|
+
const declared = /* @__PURE__ */ new Map();
|
|
4885
|
+
const order = [];
|
|
4886
|
+
for (const cell of layout.cells) {
|
|
4887
|
+
if (declared.has(cell.id)) {
|
|
4888
|
+
warn("SP015", "layout.cells", `Layout cell "${cell.id}" is declared twice; the later declaration is ignored.`);
|
|
4889
|
+
continue;
|
|
4890
|
+
}
|
|
4891
|
+
declared.set(cell.id, cell.span);
|
|
4892
|
+
order.push(cell.id);
|
|
4893
|
+
}
|
|
4894
|
+
const holder = /* @__PURE__ */ new Map();
|
|
4895
|
+
const unplaced = [];
|
|
4896
|
+
childCells.forEach((cell, index) => {
|
|
4897
|
+
if (cell === void 0) {
|
|
4898
|
+
unplaced.push(index);
|
|
4899
|
+
} else if (!declared.has(cell)) {
|
|
4900
|
+
warn("SP015", "cell", `Child ${index} names cell "${cell}", which the layout does not declare; it is placed in source order, span 1.`);
|
|
4901
|
+
unplaced.push(index);
|
|
4902
|
+
} else if (holder.has(cell)) {
|
|
4903
|
+
warn("SP015", "cell", `Children ${holder.get(cell)} and ${index} both name cell "${cell}"; the later is placed in source order, span 1.`);
|
|
4904
|
+
unplaced.push(index);
|
|
4905
|
+
} else {
|
|
4906
|
+
holder.set(cell, index);
|
|
4907
|
+
}
|
|
4908
|
+
});
|
|
4909
|
+
for (const id of order) {
|
|
4910
|
+
if (!holder.has(id)) warn("SP015", "layout.cells", `Layout cell "${id}" has no child; it is dropped.`);
|
|
4911
|
+
}
|
|
4912
|
+
const single = { sm: { col: 1, row: 1 }, md: { col: 1, row: 1 }, lg: { col: 1, row: 1 } };
|
|
4913
|
+
const base = safeIdOf(props.id);
|
|
4914
|
+
const taken = /* @__PURE__ */ new Set();
|
|
4915
|
+
const chartIdOf = (token) => {
|
|
4916
|
+
const stem = `${base}--${token.replace(UNSAFE, "-")}`;
|
|
4917
|
+
let id = stem;
|
|
4918
|
+
for (let n = 2; taken.has(id); n += 1) id = `${stem}-${n}`;
|
|
4919
|
+
taken.add(id);
|
|
4920
|
+
return id;
|
|
4921
|
+
};
|
|
4922
|
+
const cellOf = (id, child, span, token) => ({
|
|
4923
|
+
id,
|
|
4924
|
+
child,
|
|
4925
|
+
chartId: chartIdOf(token),
|
|
4926
|
+
span,
|
|
4927
|
+
nominal: nominalBox(layout, span, ssrWidth),
|
|
4928
|
+
style: cellStyle(span)
|
|
4929
|
+
});
|
|
4930
|
+
const cells = [
|
|
4931
|
+
...order.filter((id) => holder.has(id)).map((id) => cellOf(id, holder.get(id), declared.get(id), id)),
|
|
4932
|
+
...unplaced.map((index) => cellOf(String(index), index, single, String(index)))
|
|
4933
|
+
];
|
|
4934
|
+
const style = {};
|
|
4935
|
+
for (const bp of BREAKPOINTS) style[`--sp-dashboard-columns-${bp}`] = String(layout.columns[bp]);
|
|
4936
|
+
style["--sp-dashboard-row-height"] = `${layout.rowHeight}px`;
|
|
4937
|
+
style["--sp-dashboard-layout-gap"] = `${layout.gap}px`;
|
|
4938
|
+
return { id: props.id, cells, style };
|
|
4939
|
+
}
|
|
4940
|
+
function cellChartBox(cell, chartProps, recipe) {
|
|
4941
|
+
const width = chartProps.width ?? cell.width;
|
|
4942
|
+
if (chartProps.height !== void 0) return { width, height: chartProps.height };
|
|
4943
|
+
let outer;
|
|
4944
|
+
if (recipe && width > 0) {
|
|
4945
|
+
const model = recipe.build({ ...chartProps, width, height: PROBE }, { id: "sp-probe", width, locale: "en", emptyState: { text: "", rule: false }, domainPadding: 0 });
|
|
4946
|
+
if (model.status !== "deferred") outer = model.geometry.viewBox.height;
|
|
4947
|
+
}
|
|
4948
|
+
outer ??= cardLayout(chartProps, { width, areaHeight: PROBE, chrome: chartProps.chrome ?? "card", locale: "en" }).viewBox.height;
|
|
4949
|
+
return { width, height: Math.max(1, round2(cell.height - (outer - PROBE))) };
|
|
4950
|
+
}
|
|
4951
|
+
|
|
4952
|
+
// src/dashboard/view.ts
|
|
4953
|
+
function dashboardView(props, children) {
|
|
4954
|
+
const model = resolveDashboard(props, children.map((c) => c.cell));
|
|
4955
|
+
if (props.title === void 0 && props.label === void 0 && process.env.NODE_ENV !== "production") {
|
|
4956
|
+
diagnose("SP002", "Dashboard", { property: "title", message: "Name the region with `title` or `label`." });
|
|
4957
|
+
}
|
|
4958
|
+
const base = safeIdOf(props.id);
|
|
4959
|
+
const ground = props.ground ?? DEFAULTS.ground;
|
|
4960
|
+
const groundName = typeof ground === "string" ? ground : ground.name;
|
|
4961
|
+
const titled = props.title !== void 0;
|
|
4962
|
+
const heading = titled ? { level: props.headingLevel ?? DASHBOARD_DEFAULTS.headingLevel, id: `${base}-title`, text: props.title } : void 0;
|
|
4963
|
+
const description = props.description !== void 0 ? { id: `${base}-desc`, text: props.description } : void 0;
|
|
4964
|
+
const config = {};
|
|
4965
|
+
for (const key of ["ground", "substrate", "mode", "locale"]) {
|
|
4966
|
+
if (props[key] !== void 0) config[key] = props[key];
|
|
4967
|
+
}
|
|
4968
|
+
return {
|
|
4969
|
+
model,
|
|
4970
|
+
section: {
|
|
4971
|
+
className: ["sp-dashboard", `sp-ground-${groundName}`, props.className].filter(Boolean).join(" "),
|
|
4972
|
+
substrate: props.substrate ?? DEFAULTS.substrate,
|
|
4973
|
+
...heading ? { labelledby: heading.id } : { label: props.label },
|
|
4974
|
+
...description ? { describedby: description.id } : {},
|
|
4975
|
+
style: model.style
|
|
4976
|
+
},
|
|
4977
|
+
...heading ? { heading } : {},
|
|
4978
|
+
...description ? { description } : {},
|
|
4979
|
+
cells: model.cells.map((cell) => ({
|
|
4980
|
+
child: cell.child,
|
|
4981
|
+
labelledby: `${children[cell.child]?.id ?? cell.chartId}-title`,
|
|
4982
|
+
style: cell.style,
|
|
4983
|
+
context: { chartId: cell.chartId, box: cell.nominal, config }
|
|
4984
|
+
}))
|
|
4985
|
+
};
|
|
4986
|
+
}
|
|
4987
|
+
function inCell(props, cell, recipe) {
|
|
4988
|
+
if (!cell) return { props, width: props.width };
|
|
4989
|
+
const box = cellChartBox(cell.box, props, recipe);
|
|
4990
|
+
const merged = { ...props };
|
|
4991
|
+
for (const [key, value] of Object.entries(cell.config)) merged[key] ??= value;
|
|
4992
|
+
return {
|
|
4993
|
+
props: { ...merged, id: props.id ?? cell.chartId, height: props.height ?? box.height },
|
|
4994
|
+
width: props.width ?? box.width
|
|
4995
|
+
};
|
|
4996
|
+
}
|
|
4997
|
+
|
|
4998
|
+
// src/dashboard/link.ts
|
|
4999
|
+
function linkedItems(model, key, value) {
|
|
5000
|
+
const { hitAreas } = model.geometry;
|
|
5001
|
+
if (hitAreas.length > 0 && !hitAreas.some((hit) => key in hit.datum) && process.env.NODE_ENV !== "production") {
|
|
5002
|
+
diagnose("SP016", model.chart, { property: "link.key", message: `No datum has a "${key}" field.` });
|
|
5003
|
+
}
|
|
5004
|
+
return hitAreas.flatMap((hit, index) => hit.datum[key] === value ? [index] : []);
|
|
5005
|
+
}
|
|
5006
|
+
function linkFrom(key, source, active) {
|
|
5007
|
+
return active ? { key, value: active.datum[key], source } : null;
|
|
5008
|
+
}
|
|
5009
|
+
function linkedMarks(model, state) {
|
|
5010
|
+
if (!state || state.source === model.id) return [];
|
|
5011
|
+
return linkedItems(model, state.key, state.value).map((index) => readout(model, toActiveItem(model.geometry.hitAreas[index])).marker.d);
|
|
5012
|
+
}
|
|
5013
|
+
|
|
5014
|
+
export { DASHBOARD_DEFAULTS, DEFAULTS, DISPLAY_FACE_PROBE, FORCED_PRECISION_QUERY, LINE_CHART_DEMO, LINE_CHART_DEMO_KEYS, MIN_TOUCH_TARGET, NAVIGATION_KEYS, NullInker, PATH_BYTE_BUDGET, SilverpointError, __setDiagnosticSink, activityGrid, addDays, areaChart, bandScale, barChart, breakpointOf, bubbleChart, bulletChart, candlestickChart, cellChartBox, checkTypeface, chordRing, circlePath, composedChart, coxcombChart, createPrng, dashboardView, deriveSeed, diagnose, donutChart, enforceHeightening, expandDomain, extent, fnv1a32, funnelChart, gaugeArc, heatmapChart, inCell, instanceId, isoDate, kpiCard, lineChart, linearScale, linkFrom, linkedItems, linkedMarks, max, meterChart, min, orbitChart, parseGeometry, parseIsoDate, pathBytes, perBreakpoint, polarBarChart, pyramidChart, radarChart, radialArcGroup, radialRings, rangeBandChart, readout, reduceInteraction, registerInker, resolveActive, resolveConfig, resolveDashboard, resolveInker, resolveLayout, resolveSeed, round2, roundGeometry, roundPathData, sameActive, sankeyChart, scatterChart, serializeGeometry, sparklineRows, stackedBarChart, stepActive, stepChart, streamChart, svgString, toSvgPoint, toSvgView, treemapChart, volvelleChart, waterfallChart, weekday, windRose };
|
|
4769
5015
|
//# sourceMappingURL=index.js.map
|
|
4770
5016
|
//# sourceMappingURL=index.js.map
|