tempest-react-sdk 0.27.0 → 0.28.1
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/README.md +26 -2
- package/bin/lib/css/analyze.mjs +149 -0
- package/bin/lib/css/analyze.test.mjs +136 -0
- package/bin/lib/css/collect.mjs +152 -0
- package/bin/lib/css/findings.mjs +79 -0
- package/bin/lib/css/fix.e2e.test.mjs +99 -0
- package/bin/lib/css/fix.mjs +138 -0
- package/bin/lib/css/fix.test.mjs +108 -0
- package/bin/lib/css/index.mjs +16 -0
- package/bin/lib/css/parse.mjs +398 -0
- package/bin/lib/css/parse.test.mjs +146 -0
- package/bin/lib/css/properties.mjs +399 -0
- package/bin/lib/css/repetition.mjs +213 -0
- package/bin/lib/css/repetition.test.mjs +166 -0
- package/bin/lib/css/semantic.mjs +327 -0
- package/bin/lib/css/semantic.test.mjs +201 -0
- package/bin/lib/css/tokens.mjs +119 -0
- package/bin/lib/doctor/doctor.e2e.test.mjs +45 -0
- package/bin/tempest.mjs +169 -7
- package/dist/charts/scales.cjs +2 -0
- package/dist/charts/scales.cjs.map +1 -0
- package/dist/charts/scales.js +29 -0
- package/dist/charts/scales.js.map +1 -0
- package/dist/charts.cjs +1 -1
- package/dist/charts.d.ts +91 -0
- package/dist/charts.js +9 -8
- package/dist/components/BottomNavigation/BottomNavigation.module.cjs.map +1 -1
- package/dist/components/BottomNavigation/BottomNavigation.module.js.map +1 -1
- package/dist/components/Carousel/Carousel.module.cjs.map +1 -1
- package/dist/components/Carousel/Carousel.module.js.map +1 -1
- package/dist/components/CodeBlock/CodeBlock.cjs +3 -0
- package/dist/components/CodeBlock/CodeBlock.cjs.map +1 -0
- package/dist/components/CodeBlock/CodeBlock.js +53 -0
- package/dist/components/CodeBlock/CodeBlock.js.map +1 -0
- package/dist/components/CodeBlock/CodeBlock.module.cjs +2 -0
- package/dist/components/CodeBlock/CodeBlock.module.cjs.map +1 -0
- package/dist/components/CodeBlock/CodeBlock.module.js +29 -0
- package/dist/components/CodeBlock/CodeBlock.module.js.map +1 -0
- package/dist/components/CodeBlock/tokenize.cjs +3 -0
- package/dist/components/CodeBlock/tokenize.cjs.map +1 -0
- package/dist/components/CodeBlock/tokenize.js +267 -0
- package/dist/components/CodeBlock/tokenize.js.map +1 -0
- package/dist/components/Navbar/Navbar.module.cjs.map +1 -1
- package/dist/components/Navbar/Navbar.module.js.map +1 -1
- package/dist/components/QRCode/QRCode.cjs +2 -0
- package/dist/components/QRCode/QRCode.cjs.map +1 -0
- package/dist/components/QRCode/QRCode.js +49 -0
- package/dist/components/QRCode/QRCode.js.map +1 -0
- package/dist/components/QRCode/QRCode.module.cjs +2 -0
- package/dist/components/QRCode/QRCode.module.cjs.map +1 -0
- package/dist/components/QRCode/QRCode.module.js +9 -0
- package/dist/components/QRCode/QRCode.module.js.map +1 -0
- package/dist/components/QRCode/qr-encode.cjs +2 -0
- package/dist/components/QRCode/qr-encode.cjs.map +1 -0
- package/dist/components/QRCode/qr-encode.js +295 -0
- package/dist/components/QRCode/qr-encode.js.map +1 -0
- package/dist/components/QRCode/qr-tables.cjs +2 -0
- package/dist/components/QRCode/qr-tables.cjs.map +1 -0
- package/dist/components/QRCode/qr-tables.js +366 -0
- package/dist/components/QRCode/qr-tables.js.map +1 -0
- package/dist/components/ScrollArea/ScrollArea.cjs +1 -1
- package/dist/components/ScrollArea/ScrollArea.cjs.map +1 -1
- package/dist/components/ScrollArea/ScrollArea.js +22 -16
- package/dist/components/ScrollArea/ScrollArea.js.map +1 -1
- package/dist/components/ScrollArea/ScrollArea.module.cjs.map +1 -1
- package/dist/components/ScrollArea/ScrollArea.module.js.map +1 -1
- package/dist/components/Sparkline/Sparkline.cjs +2 -0
- package/dist/components/Sparkline/Sparkline.cjs.map +1 -0
- package/dist/components/Sparkline/Sparkline.js +64 -0
- package/dist/components/Sparkline/Sparkline.js.map +1 -0
- package/dist/components/Sparkline/Sparkline.module.cjs +2 -0
- package/dist/components/Sparkline/Sparkline.module.cjs.map +1 -0
- package/dist/components/Sparkline/Sparkline.module.js +10 -0
- package/dist/components/Sparkline/Sparkline.module.js.map +1 -0
- package/dist/components/Sparkline/sparkline-geometry.cjs +2 -0
- package/dist/components/Sparkline/sparkline-geometry.cjs.map +1 -0
- package/dist/components/Sparkline/sparkline-geometry.js +56 -0
- package/dist/components/Sparkline/sparkline-geometry.js.map +1 -0
- package/dist/components/Table/Table.cjs +1 -1
- package/dist/components/Table/Table.cjs.map +1 -1
- package/dist/components/Table/Table.js +37 -30
- package/dist/components/Table/Table.js.map +1 -1
- package/dist/components/Table/Table.module.cjs.map +1 -1
- package/dist/components/Table/Table.module.js.map +1 -1
- package/dist/components/VirtualList/VirtualList.cjs +1 -1
- package/dist/components/VirtualList/VirtualList.cjs.map +1 -1
- package/dist/components/VirtualList/VirtualList.js +13 -11
- package/dist/components/VirtualList/VirtualList.js.map +1 -1
- package/dist/components/VirtualList/VirtualList.module.cjs.map +1 -1
- package/dist/components/VirtualList/VirtualList.module.js.map +1 -1
- package/dist/hooks/use-scroll-overflow.cjs +2 -0
- package/dist/hooks/use-scroll-overflow.cjs.map +1 -0
- package/dist/hooks/use-scroll-overflow.js +22 -0
- package/dist/hooks/use-scroll-overflow.js.map +1 -0
- package/dist/push/utils.cjs +1 -1
- package/dist/push/utils.cjs.map +1 -1
- package/dist/push/utils.js +1 -1
- package/dist/push/utils.js.map +1 -1
- package/dist/styles.css +1 -1
- package/dist/tempest-react-sdk.cjs +1 -1
- package/dist/tempest-react-sdk.d.ts +450 -2
- package/dist/tempest-react-sdk.js +197 -190
- package/dist/theme/create-theme.cjs +3 -3
- package/dist/theme/create-theme.cjs.map +1 -1
- package/dist/theme/create-theme.js +52 -28
- package/dist/theme/create-theme.js.map +1 -1
- package/dist/theme/data-viz-ramps.cjs +2 -0
- package/dist/theme/data-viz-ramps.cjs.map +1 -0
- package/dist/theme/data-viz-ramps.js +58 -0
- package/dist/theme/data-viz-ramps.js.map +1 -0
- package/package.json +2 -1
|
@@ -0,0 +1,56 @@
|
|
|
1
|
+
//#region src/components/Sparkline/sparkline-geometry.ts
|
|
2
|
+
function e({ values: e, width: t, height: n, padding: r = 2, min: i, max: a }) {
|
|
3
|
+
let o = e.map((e, t) => ({
|
|
4
|
+
value: e,
|
|
5
|
+
index: t
|
|
6
|
+
})).filter((e) => Number.isFinite(e.value));
|
|
7
|
+
if (o.length === 0 || t <= 0 || n <= 0) return [];
|
|
8
|
+
let s = o.map((e) => e.value), c = i ?? Math.min(...s), l = (a ?? Math.max(...s)) - c, u = Math.max(0, t - r * 2), d = Math.max(0, n - r * 2), f = o.length - 1;
|
|
9
|
+
return o.map((e, t) => {
|
|
10
|
+
let n = f === 0 ? .5 : t / f, i = l === 0 ? .5 : (e.value - c) / l;
|
|
11
|
+
return {
|
|
12
|
+
x: r + n * u,
|
|
13
|
+
y: r + (1 - Math.min(1, Math.max(0, i))) * d,
|
|
14
|
+
value: e.value,
|
|
15
|
+
index: e.index
|
|
16
|
+
};
|
|
17
|
+
});
|
|
18
|
+
}
|
|
19
|
+
function t(e) {
|
|
20
|
+
if (e.length === 0) return "";
|
|
21
|
+
if (e.length === 1) {
|
|
22
|
+
let [t] = e;
|
|
23
|
+
return `M ${t.x} ${t.y} L ${t.x} ${t.y}`;
|
|
24
|
+
}
|
|
25
|
+
return e.map((e, t) => `${t === 0 ? "M" : "L"} ${e.x} ${e.y}`).join(" ");
|
|
26
|
+
}
|
|
27
|
+
function n(e, t) {
|
|
28
|
+
if (e.length === 0) return "";
|
|
29
|
+
let n = e.map((e, t) => `${t === 0 ? "M" : "L"} ${e.x} ${e.y}`).join(" "), r = e[0];
|
|
30
|
+
return `${n} L ${e[e.length - 1].x} ${t} L ${r.x} ${t} Z`;
|
|
31
|
+
}
|
|
32
|
+
function r(e, { width: t, baselineY: n, gap: r = 2 }) {
|
|
33
|
+
if (e.length === 0) return [];
|
|
34
|
+
let i = t / e.length, a = Math.max(1, Math.min(24, i - r));
|
|
35
|
+
return e.map((e) => {
|
|
36
|
+
let t = Math.max(1, Math.abs(n - e.y));
|
|
37
|
+
return {
|
|
38
|
+
x: e.x - a / 2,
|
|
39
|
+
y: Math.min(e.y, n - t),
|
|
40
|
+
width: a,
|
|
41
|
+
height: t,
|
|
42
|
+
point: e
|
|
43
|
+
};
|
|
44
|
+
});
|
|
45
|
+
}
|
|
46
|
+
function i(e, t = String) {
|
|
47
|
+
let n = e.filter((e) => Number.isFinite(e));
|
|
48
|
+
if (n.length === 0) return "Sem dados";
|
|
49
|
+
if (n.length === 1) return `Valor único: ${t(n[0])}`;
|
|
50
|
+
let r = n[0], i = n[n.length - 1], a = i > r ? "subindo" : i < r ? "descendo" : "estável";
|
|
51
|
+
return `${n.length} pontos, ${a}. Início ${t(r)}, fim ${t(i)}. Mínimo ${t(Math.min(...n))}, máximo ${t(Math.max(...n))}.`;
|
|
52
|
+
}
|
|
53
|
+
//#endregion
|
|
54
|
+
export { n as areaPath, r as barRects, i as describeSeries, t as linePath, e as sparkPoints };
|
|
55
|
+
|
|
56
|
+
//# sourceMappingURL=sparkline-geometry.js.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"sparkline-geometry.js","names":[],"sources":["../../../src/components/Sparkline/sparkline-geometry.ts"],"sourcesContent":["/** A point in the sparkline's own coordinate space. */\nexport interface SparkPoint {\n x: number;\n y: number;\n /** The datum this point came from. */\n value: number;\n /** Its position in the input series. */\n index: number;\n}\n\nexport interface SparkGeometryOptions {\n values: readonly number[];\n width: number;\n height: number;\n /** Room reserved on every side for the end marker's ring, so it is never clipped. */\n padding?: number;\n /** Force the low end of the value axis. Defaults to the series minimum. */\n min?: number;\n /** Force the high end. Defaults to the series maximum. */\n max?: number;\n}\n\n/**\n * Project a series onto the drawing box.\n *\n * `y` is inverted — SVG grows downward and a chart grows upward — and a flat series\n * is centred rather than pinned to an edge, which is the honest reading of \"no\n * variation\" and avoids dividing by a zero-height domain.\n *\n * Non-finite values are dropped rather than drawn: a `NaN` in the middle of a path\n * silently voids the whole `d` attribute and the sparkline disappears with no error.\n *\n * @param options - The series and the box to fit it in.\n * @returns The projected points, in input order.\n */\nexport function sparkPoints({\n values,\n width,\n height,\n padding = 2,\n min,\n max,\n}: SparkGeometryOptions): SparkPoint[] {\n const usable = values\n .map((value, index) => ({ value, index }))\n .filter((item) => Number.isFinite(item.value));\n if (usable.length === 0 || width <= 0 || height <= 0) return [];\n\n const numbers = usable.map((item) => item.value);\n const lo = min ?? Math.min(...numbers);\n const hi = max ?? Math.max(...numbers);\n const span = hi - lo;\n\n const innerW = Math.max(0, width - padding * 2);\n const innerH = Math.max(0, height - padding * 2);\n const lastIndex = usable.length - 1;\n\n return usable.map((item, i) => {\n const t = lastIndex === 0 ? 0.5 : i / lastIndex;\n const v = span === 0 ? 0.5 : (item.value - lo) / span;\n return {\n x: padding + t * innerW,\n y: padding + (1 - Math.min(1, Math.max(0, v))) * innerH,\n value: item.value,\n index: item.index,\n };\n });\n}\n\n/** An SVG `d` for a polyline through the points. */\nexport function linePath(points: readonly SparkPoint[]): string {\n if (points.length === 0) return \"\";\n if (points.length === 1) {\n // A lone point has no line; emit a zero-length segment so the round cap\n // still paints a dot rather than nothing at all.\n const [only] = points;\n return `M ${only.x} ${only.y} L ${only.x} ${only.y}`;\n }\n return points.map((p, i) => `${i === 0 ? \"M\" : \"L\"} ${p.x} ${p.y}`).join(\" \");\n}\n\n/**\n * An SVG `d` for the area under the line, closed along the baseline.\n *\n * @param points - The projected points.\n * @param baselineY - Where the fill closes, in the same space as the points.\n */\nexport function areaPath(points: readonly SparkPoint[], baselineY: number): string {\n if (points.length === 0) return \"\";\n const line = points.map((p, i) => `${i === 0 ? \"M\" : \"L\"} ${p.x} ${p.y}`).join(\" \");\n const first = points[0];\n const last = points[points.length - 1];\n return `${line} L ${last.x} ${baselineY} L ${first.x} ${baselineY} Z`;\n}\n\n/** Bar rectangles growing from the baseline, with the band's leftover left as air. */\nexport function barRects(\n points: readonly SparkPoint[],\n { width, baselineY, gap = 2 }: { width: number; baselineY: number; gap?: number },\n): { x: number; y: number; width: number; height: number; point: SparkPoint }[] {\n if (points.length === 0) return [];\n const band = width / points.length;\n // Never fill the slot: the gap between bars is what separates them, not a stroke.\n const barWidth = Math.max(1, Math.min(24, band - gap));\n return points.map((point) => {\n /*\n * The minimum value sits on the baseline, where the raw height is 0. It still\n * needs a visible sliver — but growing *up* from the baseline, not down: the\n * naive `Math.max(1, …)` on height alone leaves the bar hanging one pixel\n * below the axis it is supposed to stand on.\n */\n const height = Math.max(1, Math.abs(baselineY - point.y));\n return {\n x: point.x - barWidth / 2,\n y: Math.min(point.y, baselineY - height),\n width: barWidth,\n height,\n point,\n };\n });\n}\n\n/**\n * A one-sentence description of the series, for the chart's accessible name.\n *\n * A sparkline has no axes and no legend, so without this it is an unlabelled image:\n * a screen reader reaches it and reads nothing. Direction is stated in words rather\n * than implied by the shape.\n *\n * @param values - The series, in order.\n * @param format - How to render a single value.\n * @returns Text suitable for `aria-label`.\n */\nexport function describeSeries(\n values: readonly number[],\n format: (value: number) => string = String,\n): string {\n const usable = values.filter((v) => Number.isFinite(v));\n if (usable.length === 0) return \"Sem dados\";\n if (usable.length === 1) return `Valor único: ${format(usable[0])}`;\n\n const first = usable[0];\n const last = usable[usable.length - 1];\n const direction = last > first ? \"subindo\" : last < first ? \"descendo\" : \"estável\";\n return (\n `${usable.length} pontos, ${direction}. ` +\n `Início ${format(first)}, fim ${format(last)}. ` +\n `Mínimo ${format(Math.min(...usable))}, máximo ${format(Math.max(...usable))}.`\n );\n}\n"],"mappings":";AAmCA,SAAgB,EAAY,EACxB,WACA,UACA,WACA,aAAU,GACV,QACA,UACmC;CACnC,IAAM,IAAS,EACV,KAAK,GAAO,OAAW;EAAE;EAAO;CAAM,EAAE,CAAC,CACzC,QAAQ,MAAS,OAAO,SAAS,EAAK,KAAK,CAAC;CACjD,IAAI,EAAO,WAAW,KAAK,KAAS,KAAK,KAAU,GAAG,OAAO,CAAC;CAE9D,IAAM,IAAU,EAAO,KAAK,MAAS,EAAK,KAAK,GACzC,IAAK,KAAO,KAAK,IAAI,GAAG,CAAO,GAE/B,KADK,KAAO,KAAK,IAAI,GAAG,CAAO,KACnB,GAEZ,IAAS,KAAK,IAAI,GAAG,IAAQ,IAAU,CAAC,GACxC,IAAS,KAAK,IAAI,GAAG,IAAS,IAAU,CAAC,GACzC,IAAY,EAAO,SAAS;CAElC,OAAO,EAAO,KAAK,GAAM,MAAM;EAC3B,IAAM,IAAI,MAAc,IAAI,KAAM,IAAI,GAChC,IAAI,MAAS,IAAI,MAAO,EAAK,QAAQ,KAAM;EACjD,OAAO;GACH,GAAG,IAAU,IAAI;GACjB,GAAG,KAAW,IAAI,KAAK,IAAI,GAAG,KAAK,IAAI,GAAG,CAAC,CAAC,KAAK;GACjD,OAAO,EAAK;GACZ,OAAO,EAAK;EAChB;CACJ,CAAC;AACL;AAGA,SAAgB,EAAS,GAAuC;CAC5D,IAAI,EAAO,WAAW,GAAG,OAAO;CAChC,IAAI,EAAO,WAAW,GAAG;EAGrB,IAAM,CAAC,KAAQ;EACf,OAAO,KAAK,EAAK,EAAE,GAAG,EAAK,EAAE,KAAK,EAAK,EAAE,GAAG,EAAK;CACrD;CACA,OAAO,EAAO,KAAK,GAAG,MAAM,GAAG,MAAM,IAAI,MAAM,IAAI,GAAG,EAAE,EAAE,GAAG,EAAE,GAAG,CAAC,CAAC,KAAK,GAAG;AAChF;AAQA,SAAgB,EAAS,GAA+B,GAA2B;CAC/E,IAAI,EAAO,WAAW,GAAG,OAAO;CAChC,IAAM,IAAO,EAAO,KAAK,GAAG,MAAM,GAAG,MAAM,IAAI,MAAM,IAAI,GAAG,EAAE,EAAE,GAAG,EAAE,GAAG,CAAC,CAAC,KAAK,GAAG,GAC5E,IAAQ,EAAO;CAErB,OAAO,GAAG,EAAK,KADF,EAAO,EAAO,SAAS,EAChB,CAAK,EAAE,GAAG,EAAU,KAAK,EAAM,EAAE,GAAG,EAAU;AACtE;AAGA,SAAgB,EACZ,GACA,EAAE,UAAO,cAAW,SAAM,KACkD;CAC5E,IAAI,EAAO,WAAW,GAAG,OAAO,CAAC;CACjC,IAAM,IAAO,IAAQ,EAAO,QAEtB,IAAW,KAAK,IAAI,GAAG,KAAK,IAAI,IAAI,IAAO,CAAG,CAAC;CACrD,OAAO,EAAO,KAAK,MAAU;EAOzB,IAAM,IAAS,KAAK,IAAI,GAAG,KAAK,IAAI,IAAY,EAAM,CAAC,CAAC;EACxD,OAAO;GACH,GAAG,EAAM,IAAI,IAAW;GACxB,GAAG,KAAK,IAAI,EAAM,GAAG,IAAY,CAAM;GACvC,OAAO;GACP;GACA;EACJ;CACJ,CAAC;AACL;AAaA,SAAgB,EACZ,GACA,IAAoC,QAC9B;CACN,IAAM,IAAS,EAAO,QAAQ,MAAM,OAAO,SAAS,CAAC,CAAC;CACtD,IAAI,EAAO,WAAW,GAAG,OAAO;CAChC,IAAI,EAAO,WAAW,GAAG,OAAO,gBAAgB,EAAO,EAAO,EAAE;CAEhE,IAAM,IAAQ,EAAO,IACf,IAAO,EAAO,EAAO,SAAS,IAC9B,IAAY,IAAO,IAAQ,YAAY,IAAO,IAAQ,aAAa;CACzE,OACI,GAAG,EAAO,OAAO,WAAW,EAAU,WAC5B,EAAO,CAAK,EAAE,QAAQ,EAAO,CAAI,EAAE,WACnC,EAAO,KAAK,IAAI,GAAG,CAAM,CAAC,EAAE,WAAW,EAAO,KAAK,IAAI,GAAG,CAAM,CAAC,EAAE;AAErF"}
|
|
@@ -1,2 +1,2 @@
|
|
|
1
|
-
const e=require("../../utils/cn.cjs"),t=require("./Table.module.cjs");let
|
|
1
|
+
const e=require("../../utils/cn.cjs"),t=require("../../hooks/use-scroll-overflow.cjs"),n=require("./Table.module.cjs");let r=require("react"),i=require("react/jsx-runtime");function a(e){if(e===`tablet`)return n.default.priorityTablet;if(e===`desktop`)return n.default.priorityDesktop}function o({columns:o,data:s,rowKey:c,onRowClick:l,emptyMessage:u=`Nenhum registro encontrado.`,className:d,stackOnMobile:f=!1,scrollLabel:p=`Tabela rolável horizontalmente`}){let m=(0,r.useRef)(null),h=t.useScrollOverflow(m,`horizontal`);return(0,i.jsx)(`div`,{ref:m,className:e.cn(n.default.scroll,f&&n.default.stackable,d),tabIndex:h?0:void 0,role:h?`group`:void 0,"aria-label":h?p:void 0,children:(0,i.jsxs)(`table`,{className:n.default.table,children:[(0,i.jsx)(`thead`,{className:e.cn(f&&n.default.stackableHead),children:(0,i.jsx)(`tr`,{children:o.map(t=>(0,i.jsx)(`th`,{className:e.cn(n.default.th,t.align===`right`&&n.default.alignRight,t.align===`center`&&n.default.alignCenter,a(t.priority)),style:{width:t.width},children:t.header},t.key))})}),(0,i.jsx)(`tbody`,{children:s.length===0?(0,i.jsx)(`tr`,{children:(0,i.jsx)(`td`,{className:n.default.emptyRow,colSpan:o.length,children:u})}):s.map((t,r)=>(0,i.jsx)(`tr`,{className:e.cn(n.default.tr,l&&n.default.clickable,f&&n.default.stackableRow),onClick:l?()=>l(t):void 0,children:o.map(o=>{let s=o.render?o.render(t,r):t[o.key];return(0,i.jsx)(`td`,{className:e.cn(n.default.td,o.align===`right`&&n.default.alignRight,o.align===`center`&&n.default.alignCenter,a(o.priority),o.className),"data-label":typeof o.header==`string`?o.header:void 0,children:s},o.key)})},c(t,r)))})]})})}exports.Table=o;
|
|
2
2
|
//# sourceMappingURL=Table.cjs.map
|
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"Table.cjs","names":[],"sources":["../../../src/components/Table/Table.tsx"],"sourcesContent":["import type { ReactNode } from \"react\";\nimport { cn } from \"@/utils/cn\";\nimport styles from \"./Table.module.css\";\n\nexport type TableAlign = \"left\" | \"right\" | \"center\";\nexport type TablePriority = \"always\" | \"tablet\" | \"desktop\";\n\nexport interface TableColumn<T> {\n key: string;\n header: ReactNode;\n /** Render the cell content. Defaults to `row[key]` if not provided. */\n render?: (row: T, index: number) => ReactNode;\n align?: TableAlign;\n width?: string | number;\n className?: string;\n /**\n * Visibility priority: `always` (default) shows on every viewport,\n * `tablet` hides below md (< 768px), `desktop` hides below lg (< 1024px).\n */\n priority?: TablePriority;\n}\n\nexport interface TableProps<T> {\n columns: TableColumn<T>[];\n data: T[];\n rowKey: (row: T, index: number) => string | number;\n onRowClick?: (row: T) => void;\n emptyMessage?: ReactNode;\n className?: string;\n /**\n * Stack mode — render rows as label/value cards on mobile (< md).\n * Better than horizontal scroll when each row has 3+ columns of dense data.\n */\n stackOnMobile?: boolean;\n}\n\nfunction priorityClass(priority: TablePriority | undefined): string | undefined {\n if (priority === \"tablet\") return styles.priorityTablet;\n if (priority === \"desktop\") return styles.priorityDesktop;\n return undefined;\n}\n\n/**\n * Lightweight table with declarative columns + mobile niceties.\n *\n * - `priority` per column lets less-important data hide on narrow viewports.\n * - `stackOnMobile` re-renders each row as a label/value card on mobile,\n * avoiding horizontal scroll for dense data.\n */\nexport function Table<T>({\n columns,\n data,\n rowKey,\n onRowClick,\n emptyMessage = \"Nenhum registro encontrado.\",\n className,\n stackOnMobile = false,\n}: TableProps<T>) {\n return (\n <div
|
|
1
|
+
{"version":3,"file":"Table.cjs","names":[],"sources":["../../../src/components/Table/Table.tsx"],"sourcesContent":["import { useRef } from \"react\";\nimport type { ReactNode } from \"react\";\nimport { cn } from \"@/utils/cn\";\nimport { useScrollOverflow } from \"@/hooks/use-scroll-overflow\";\nimport styles from \"./Table.module.css\";\n\nexport type TableAlign = \"left\" | \"right\" | \"center\";\nexport type TablePriority = \"always\" | \"tablet\" | \"desktop\";\n\nexport interface TableColumn<T> {\n key: string;\n header: ReactNode;\n /** Render the cell content. Defaults to `row[key]` if not provided. */\n render?: (row: T, index: number) => ReactNode;\n align?: TableAlign;\n width?: string | number;\n className?: string;\n /**\n * Visibility priority: `always` (default) shows on every viewport,\n * `tablet` hides below md (< 768px), `desktop` hides below lg (< 1024px).\n */\n priority?: TablePriority;\n}\n\nexport interface TableProps<T> {\n columns: TableColumn<T>[];\n data: T[];\n rowKey: (row: T, index: number) => string | number;\n onRowClick?: (row: T) => void;\n emptyMessage?: ReactNode;\n className?: string;\n /**\n * Stack mode — render rows as label/value cards on mobile (< md).\n * Better than horizontal scroll when each row has 3+ columns of dense data.\n */\n stackOnMobile?: boolean;\n /**\n * Accessible name for the scrollable region, used only while the table is\n * actually wider than its box. A focus stop that announces nothing is worse\n * than no focus stop, so name the table when the page holds several.\n */\n scrollLabel?: string;\n}\n\nfunction priorityClass(priority: TablePriority | undefined): string | undefined {\n if (priority === \"tablet\") return styles.priorityTablet;\n if (priority === \"desktop\") return styles.priorityDesktop;\n return undefined;\n}\n\n/**\n * Lightweight table with declarative columns + mobile niceties.\n *\n * - `priority` per column lets less-important data hide on narrow viewports.\n * - `stackOnMobile` re-renders each row as a label/value card on mobile,\n * avoiding horizontal scroll for dense data.\n */\nexport function Table<T>({\n columns,\n data,\n rowKey,\n onRowClick,\n emptyMessage = \"Nenhum registro encontrado.\",\n className,\n stackOnMobile = false,\n scrollLabel = \"Tabela rolável horizontalmente\",\n}: TableProps<T>) {\n const scrollRef = useRef<HTMLDivElement>(null);\n const scrollable = useScrollOverflow(scrollRef, \"horizontal\");\n\n return (\n <div\n ref={scrollRef}\n className={cn(styles.scroll, stackOnMobile && styles.stackable, className)}\n tabIndex={scrollable ? 0 : undefined}\n role={scrollable ? \"group\" : undefined}\n aria-label={scrollable ? scrollLabel : undefined}\n >\n <table className={styles.table}>\n <thead className={cn(stackOnMobile && styles.stackableHead)}>\n <tr>\n {columns.map((column) => (\n <th\n key={column.key}\n className={cn(\n styles.th,\n column.align === \"right\" && styles.alignRight,\n column.align === \"center\" && styles.alignCenter,\n priorityClass(column.priority),\n )}\n style={{ width: column.width }}\n >\n {column.header}\n </th>\n ))}\n </tr>\n </thead>\n <tbody>\n {data.length === 0 ? (\n <tr>\n <td className={styles.emptyRow} colSpan={columns.length}>\n {emptyMessage}\n </td>\n </tr>\n ) : (\n data.map((row, index) => (\n <tr\n key={rowKey(row, index)}\n className={cn(\n styles.tr,\n onRowClick && styles.clickable,\n stackOnMobile && styles.stackableRow,\n )}\n onClick={onRowClick ? () => onRowClick(row) : undefined}\n >\n {columns.map((column) => {\n const content = column.render\n ? column.render(row, index)\n : (row as Record<string, ReactNode>)[column.key];\n return (\n <td\n key={column.key}\n className={cn(\n styles.td,\n column.align === \"right\" && styles.alignRight,\n column.align === \"center\" && styles.alignCenter,\n priorityClass(column.priority),\n column.className,\n )}\n data-label={\n typeof column.header === \"string\"\n ? column.header\n : undefined\n }\n >\n {content}\n </td>\n );\n })}\n </tr>\n ))\n )}\n </tbody>\n </table>\n </div>\n );\n}\n"],"mappings":"6KA4CA,SAAS,EAAc,EAAyD,CAC5E,GAAI,IAAa,SAAU,OAAO,EAAA,QAAO,eACzC,GAAI,IAAa,UAAW,OAAO,EAAA,QAAO,eAE9C,CASA,SAAgB,EAAS,CACrB,UACA,OACA,SACA,aACA,eAAe,8BACf,YACA,gBAAgB,GAChB,cAAc,kCACA,CACd,IAAM,GAAA,EAAA,EAAA,OAAA,CAAmC,IAAI,EACvC,EAAa,EAAA,kBAAkB,EAAW,YAAY,EAE5D,OACI,EAAA,EAAA,IAAA,CAAC,MAAD,CACI,IAAK,EACL,UAAW,EAAA,GAAG,EAAA,QAAO,OAAQ,GAAiB,EAAA,QAAO,UAAW,CAAS,EACzE,SAAU,EAAa,EAAI,IAAA,GAC3B,KAAM,EAAa,QAAU,IAAA,GAC7B,aAAY,EAAa,EAAc,IAAA,aAEvC,EAAA,EAAA,KAAA,CAAC,QAAD,CAAO,UAAW,EAAA,QAAO,eAAzB,EACI,EAAA,EAAA,IAAA,CAAC,QAAD,CAAO,UAAW,EAAA,GAAG,GAAiB,EAAA,QAAO,aAAa,YACtD,EAAA,EAAA,IAAA,CAAC,KAAD,CAAA,SACK,EAAQ,IAAK,IACV,EAAA,EAAA,IAAA,CAAC,KAAD,CAEI,UAAW,EAAA,GACP,EAAA,QAAO,GACP,EAAO,QAAU,SAAW,EAAA,QAAO,WACnC,EAAO,QAAU,UAAY,EAAA,QAAO,YACpC,EAAc,EAAO,QAAQ,CACjC,EACA,MAAO,CAAE,MAAO,EAAO,KAAM,WAE5B,EAAO,MACR,EAVK,EAAO,GAUZ,CACP,CACD,CAAA,CACD,CAAA,GACP,EAAA,EAAA,IAAA,CAAC,QAAD,CAAA,SACK,EAAK,SAAW,GACb,EAAA,EAAA,IAAA,CAAC,KAAD,CAAA,UACI,EAAA,EAAA,IAAA,CAAC,KAAD,CAAI,UAAW,EAAA,QAAO,SAAU,QAAS,EAAQ,gBAC5C,CACD,CAAA,CACJ,CAAA,EAEJ,EAAK,KAAK,EAAK,KACX,EAAA,EAAA,IAAA,CAAC,KAAD,CAEI,UAAW,EAAA,GACP,EAAA,QAAO,GACP,GAAc,EAAA,QAAO,UACrB,GAAiB,EAAA,QAAO,YAC5B,EACA,QAAS,MAAmB,EAAW,CAAG,EAAI,IAAA,YAE7C,EAAQ,IAAK,GAAW,CACrB,IAAM,EAAU,EAAO,OACjB,EAAO,OAAO,EAAK,CAAK,EACvB,EAAkC,EAAO,KAChD,OACI,EAAA,EAAA,IAAA,CAAC,KAAD,CAEI,UAAW,EAAA,GACP,EAAA,QAAO,GACP,EAAO,QAAU,SAAW,EAAA,QAAO,WACnC,EAAO,QAAU,UAAY,EAAA,QAAO,YACpC,EAAc,EAAO,QAAQ,EAC7B,EAAO,SACX,EACA,aACI,OAAO,EAAO,QAAW,SACnB,EAAO,OACP,IAAA,YAGT,CACD,EAfK,EAAO,GAeZ,CAEZ,CAAC,CACD,EAhCK,EAAO,EAAK,CAAK,CAgCtB,CACP,CAEF,CAAA,CACJ,GACN,CAAA,CAEb"}
|
|
@@ -1,43 +1,50 @@
|
|
|
1
1
|
import { cn as e } from "../../utils/cn.js";
|
|
2
|
-
import t from "
|
|
3
|
-
import
|
|
2
|
+
import { useScrollOverflow as t } from "../../hooks/use-scroll-overflow.js";
|
|
3
|
+
import n from "./Table.module.js";
|
|
4
|
+
import { useRef as r } from "react";
|
|
5
|
+
import { jsx as i, jsxs as a } from "react/jsx-runtime";
|
|
4
6
|
//#region src/components/Table/Table.tsx
|
|
5
|
-
function
|
|
6
|
-
if (e === "tablet") return
|
|
7
|
-
if (e === "desktop") return
|
|
7
|
+
function o(e) {
|
|
8
|
+
if (e === "tablet") return n.priorityTablet;
|
|
9
|
+
if (e === "desktop") return n.priorityDesktop;
|
|
8
10
|
}
|
|
9
|
-
function
|
|
10
|
-
|
|
11
|
-
|
|
12
|
-
|
|
13
|
-
|
|
14
|
-
|
|
15
|
-
|
|
16
|
-
|
|
17
|
-
|
|
18
|
-
|
|
19
|
-
|
|
20
|
-
|
|
21
|
-
|
|
22
|
-
|
|
23
|
-
|
|
24
|
-
|
|
25
|
-
|
|
26
|
-
|
|
27
|
-
|
|
28
|
-
|
|
29
|
-
|
|
30
|
-
|
|
31
|
-
|
|
11
|
+
function s({ columns: s, data: c, rowKey: l, onRowClick: u, emptyMessage: d = "Nenhum registro encontrado.", className: f, stackOnMobile: p = !1, scrollLabel: m = "Tabela rolável horizontalmente" }) {
|
|
12
|
+
let h = r(null), g = t(h, "horizontal");
|
|
13
|
+
return /* @__PURE__ */ i("div", {
|
|
14
|
+
ref: h,
|
|
15
|
+
className: e(n.scroll, p && n.stackable, f),
|
|
16
|
+
tabIndex: g ? 0 : void 0,
|
|
17
|
+
role: g ? "group" : void 0,
|
|
18
|
+
"aria-label": g ? m : void 0,
|
|
19
|
+
children: /* @__PURE__ */ a("table", {
|
|
20
|
+
className: n.table,
|
|
21
|
+
children: [/* @__PURE__ */ i("thead", {
|
|
22
|
+
className: e(p && n.stackableHead),
|
|
23
|
+
children: /* @__PURE__ */ i("tr", { children: s.map((t) => /* @__PURE__ */ i("th", {
|
|
24
|
+
className: e(n.th, t.align === "right" && n.alignRight, t.align === "center" && n.alignCenter, o(t.priority)),
|
|
25
|
+
style: { width: t.width },
|
|
26
|
+
children: t.header
|
|
27
|
+
}, t.key)) })
|
|
28
|
+
}), /* @__PURE__ */ i("tbody", { children: c.length === 0 ? /* @__PURE__ */ i("tr", { children: /* @__PURE__ */ i("td", {
|
|
29
|
+
className: n.emptyRow,
|
|
30
|
+
colSpan: s.length,
|
|
31
|
+
children: d
|
|
32
|
+
}) }) : c.map((t, r) => /* @__PURE__ */ i("tr", {
|
|
33
|
+
className: e(n.tr, u && n.clickable, p && n.stackableRow),
|
|
34
|
+
onClick: u ? () => u(t) : void 0,
|
|
35
|
+
children: s.map((a) => {
|
|
36
|
+
let s = a.render ? a.render(t, r) : t[a.key];
|
|
37
|
+
return /* @__PURE__ */ i("td", {
|
|
38
|
+
className: e(n.td, a.align === "right" && n.alignRight, a.align === "center" && n.alignCenter, o(a.priority), a.className),
|
|
32
39
|
"data-label": typeof a.header == "string" ? a.header : void 0,
|
|
33
40
|
children: s
|
|
34
41
|
}, a.key);
|
|
35
42
|
})
|
|
36
|
-
},
|
|
43
|
+
}, l(t, r))) })]
|
|
37
44
|
})
|
|
38
45
|
});
|
|
39
46
|
}
|
|
40
47
|
//#endregion
|
|
41
|
-
export {
|
|
48
|
+
export { s as Table };
|
|
42
49
|
|
|
43
50
|
//# sourceMappingURL=Table.js.map
|
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"Table.js","names":[],"sources":["../../../src/components/Table/Table.tsx"],"sourcesContent":["import type { ReactNode } from \"react\";\nimport { cn } from \"@/utils/cn\";\nimport styles from \"./Table.module.css\";\n\nexport type TableAlign = \"left\" | \"right\" | \"center\";\nexport type TablePriority = \"always\" | \"tablet\" | \"desktop\";\n\nexport interface TableColumn<T> {\n key: string;\n header: ReactNode;\n /** Render the cell content. Defaults to `row[key]` if not provided. */\n render?: (row: T, index: number) => ReactNode;\n align?: TableAlign;\n width?: string | number;\n className?: string;\n /**\n * Visibility priority: `always` (default) shows on every viewport,\n * `tablet` hides below md (< 768px), `desktop` hides below lg (< 1024px).\n */\n priority?: TablePriority;\n}\n\nexport interface TableProps<T> {\n columns: TableColumn<T>[];\n data: T[];\n rowKey: (row: T, index: number) => string | number;\n onRowClick?: (row: T) => void;\n emptyMessage?: ReactNode;\n className?: string;\n /**\n * Stack mode — render rows as label/value cards on mobile (< md).\n * Better than horizontal scroll when each row has 3+ columns of dense data.\n */\n stackOnMobile?: boolean;\n}\n\nfunction priorityClass(priority: TablePriority | undefined): string | undefined {\n if (priority === \"tablet\") return styles.priorityTablet;\n if (priority === \"desktop\") return styles.priorityDesktop;\n return undefined;\n}\n\n/**\n * Lightweight table with declarative columns + mobile niceties.\n *\n * - `priority` per column lets less-important data hide on narrow viewports.\n * - `stackOnMobile` re-renders each row as a label/value card on mobile,\n * avoiding horizontal scroll for dense data.\n */\nexport function Table<T>({\n columns,\n data,\n rowKey,\n onRowClick,\n emptyMessage = \"Nenhum registro encontrado.\",\n className,\n stackOnMobile = false,\n}: TableProps<T>) {\n return (\n <div
|
|
1
|
+
{"version":3,"file":"Table.js","names":[],"sources":["../../../src/components/Table/Table.tsx"],"sourcesContent":["import { useRef } from \"react\";\nimport type { ReactNode } from \"react\";\nimport { cn } from \"@/utils/cn\";\nimport { useScrollOverflow } from \"@/hooks/use-scroll-overflow\";\nimport styles from \"./Table.module.css\";\n\nexport type TableAlign = \"left\" | \"right\" | \"center\";\nexport type TablePriority = \"always\" | \"tablet\" | \"desktop\";\n\nexport interface TableColumn<T> {\n key: string;\n header: ReactNode;\n /** Render the cell content. Defaults to `row[key]` if not provided. */\n render?: (row: T, index: number) => ReactNode;\n align?: TableAlign;\n width?: string | number;\n className?: string;\n /**\n * Visibility priority: `always` (default) shows on every viewport,\n * `tablet` hides below md (< 768px), `desktop` hides below lg (< 1024px).\n */\n priority?: TablePriority;\n}\n\nexport interface TableProps<T> {\n columns: TableColumn<T>[];\n data: T[];\n rowKey: (row: T, index: number) => string | number;\n onRowClick?: (row: T) => void;\n emptyMessage?: ReactNode;\n className?: string;\n /**\n * Stack mode — render rows as label/value cards on mobile (< md).\n * Better than horizontal scroll when each row has 3+ columns of dense data.\n */\n stackOnMobile?: boolean;\n /**\n * Accessible name for the scrollable region, used only while the table is\n * actually wider than its box. A focus stop that announces nothing is worse\n * than no focus stop, so name the table when the page holds several.\n */\n scrollLabel?: string;\n}\n\nfunction priorityClass(priority: TablePriority | undefined): string | undefined {\n if (priority === \"tablet\") return styles.priorityTablet;\n if (priority === \"desktop\") return styles.priorityDesktop;\n return undefined;\n}\n\n/**\n * Lightweight table with declarative columns + mobile niceties.\n *\n * - `priority` per column lets less-important data hide on narrow viewports.\n * - `stackOnMobile` re-renders each row as a label/value card on mobile,\n * avoiding horizontal scroll for dense data.\n */\nexport function Table<T>({\n columns,\n data,\n rowKey,\n onRowClick,\n emptyMessage = \"Nenhum registro encontrado.\",\n className,\n stackOnMobile = false,\n scrollLabel = \"Tabela rolável horizontalmente\",\n}: TableProps<T>) {\n const scrollRef = useRef<HTMLDivElement>(null);\n const scrollable = useScrollOverflow(scrollRef, \"horizontal\");\n\n return (\n <div\n ref={scrollRef}\n className={cn(styles.scroll, stackOnMobile && styles.stackable, className)}\n tabIndex={scrollable ? 0 : undefined}\n role={scrollable ? \"group\" : undefined}\n aria-label={scrollable ? scrollLabel : undefined}\n >\n <table className={styles.table}>\n <thead className={cn(stackOnMobile && styles.stackableHead)}>\n <tr>\n {columns.map((column) => (\n <th\n key={column.key}\n className={cn(\n styles.th,\n column.align === \"right\" && styles.alignRight,\n column.align === \"center\" && styles.alignCenter,\n priorityClass(column.priority),\n )}\n style={{ width: column.width }}\n >\n {column.header}\n </th>\n ))}\n </tr>\n </thead>\n <tbody>\n {data.length === 0 ? (\n <tr>\n <td className={styles.emptyRow} colSpan={columns.length}>\n {emptyMessage}\n </td>\n </tr>\n ) : (\n data.map((row, index) => (\n <tr\n key={rowKey(row, index)}\n className={cn(\n styles.tr,\n onRowClick && styles.clickable,\n stackOnMobile && styles.stackableRow,\n )}\n onClick={onRowClick ? () => onRowClick(row) : undefined}\n >\n {columns.map((column) => {\n const content = column.render\n ? column.render(row, index)\n : (row as Record<string, ReactNode>)[column.key];\n return (\n <td\n key={column.key}\n className={cn(\n styles.td,\n column.align === \"right\" && styles.alignRight,\n column.align === \"center\" && styles.alignCenter,\n priorityClass(column.priority),\n column.className,\n )}\n data-label={\n typeof column.header === \"string\"\n ? column.header\n : undefined\n }\n >\n {content}\n </td>\n );\n })}\n </tr>\n ))\n )}\n </tbody>\n </table>\n </div>\n );\n}\n"],"mappings":";;;;;;AA4CA,SAAS,EAAc,GAAyD;CAC5E,IAAI,MAAa,UAAU,OAAO,EAAO;CACzC,IAAI,MAAa,WAAW,OAAO,EAAO;AAE9C;AASA,SAAgB,EAAS,EACrB,YACA,SACA,WACA,eACA,kBAAe,+BACf,cACA,mBAAgB,IAChB,iBAAc,oCACA;CACd,IAAM,IAAY,EAAuB,IAAI,GACvC,IAAa,EAAkB,GAAW,YAAY;CAE5D,OACI,kBAAC,OAAD;EACI,KAAK;EACL,WAAW,EAAG,EAAO,QAAQ,KAAiB,EAAO,WAAW,CAAS;EACzE,UAAU,IAAa,IAAI,KAAA;EAC3B,MAAM,IAAa,UAAU,KAAA;EAC7B,cAAY,IAAa,IAAc,KAAA;YAEvC,kBAAC,SAAD;GAAO,WAAW,EAAO;aAAzB,CACI,kBAAC,SAAD;IAAO,WAAW,EAAG,KAAiB,EAAO,aAAa;cACtD,kBAAC,MAAD,EAAA,UACK,EAAQ,KAAK,MACV,kBAAC,MAAD;KAEI,WAAW,EACP,EAAO,IACP,EAAO,UAAU,WAAW,EAAO,YACnC,EAAO,UAAU,YAAY,EAAO,aACpC,EAAc,EAAO,QAAQ,CACjC;KACA,OAAO,EAAE,OAAO,EAAO,MAAM;eAE5B,EAAO;IACR,GAVK,EAAO,GAUZ,CACP,EACD,CAAA;GACD,CAAA,GACP,kBAAC,SAAD,EAAA,UACK,EAAK,WAAW,IACb,kBAAC,MAAD,EAAA,UACI,kBAAC,MAAD;IAAI,WAAW,EAAO;IAAU,SAAS,EAAQ;cAC5C;GACD,CAAA,EACJ,CAAA,IAEJ,EAAK,KAAK,GAAK,MACX,kBAAC,MAAD;IAEI,WAAW,EACP,EAAO,IACP,KAAc,EAAO,WACrB,KAAiB,EAAO,YAC5B;IACA,SAAS,UAAmB,EAAW,CAAG,IAAI,KAAA;cAE7C,EAAQ,KAAK,MAAW;KACrB,IAAM,IAAU,EAAO,SACjB,EAAO,OAAO,GAAK,CAAK,IACvB,EAAkC,EAAO;KAChD,OACI,kBAAC,MAAD;MAEI,WAAW,EACP,EAAO,IACP,EAAO,UAAU,WAAW,EAAO,YACnC,EAAO,UAAU,YAAY,EAAO,aACpC,EAAc,EAAO,QAAQ,GAC7B,EAAO,SACX;MACA,cACI,OAAO,EAAO,UAAW,WACnB,EAAO,SACP,KAAA;gBAGT;KACD,GAfK,EAAO,GAeZ;IAEZ,CAAC;GACD,GAhCK,EAAO,GAAK,CAAK,CAgCtB,CACP,EAEF,CAAA,CACJ;;CACN,CAAA;AAEb"}
|
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"Table.module.cjs","names":[],"sources":["../../../src/components/Table/Table.module.css"],"sourcesContent":[".scroll {\n width: 100%;\n overflow-x: auto;\n border: 1px solid var(--tempest-border);\n border-radius: var(--tempest-radius-lg);\n background-color: var(--tempest-bg);\n box-shadow: var(--tempest-shadow-xs);\n}\n\n.table {\n width: 100%;\n border-collapse: collapse;\n font-family: var(--tempest-font-sans);\n font-size: var(--tempest-text-base);\n line-height: var(--tempest-leading-snug);\n}\n\n.th,\n.td {\n padding: var(--tempest-space-3) var(--tempest-space-4);\n text-align: left;\n border-bottom: 1px solid var(--tempest-border);\n}\n\n.th {\n background-color: var(--tempest-surface);\n color: var(--tempest-text-muted);\n font-weight: var(--tempest-weight-semibold);\n font-size: var(--tempest-text-xs);\n letter-spacing: var(--tempest-tracking-wider);\n text-transform: uppercase;\n white-space: nowrap;\n}\n\n.tr:last-child .td {\n border-bottom: none;\n}\n\n.tr.clickable {\n cursor: pointer;\n transition: background-color var(--tempest-duration-fast) var(--tempest-ease-out);\n}\n\n@media (hover: hover) and (pointer: fine) {\n .tr.clickable:hover {\n background-color: var(--tempest-surface);\n }\n}\n\n.tr.clickable:focus-visible {\n outline: var(--tempest-focus-ring-width) solid var(--tempest-focus-ring-color);\n outline-offset: -2px;\n}\n\n.alignRight {\n text-align: right;\n}\n\n.alignCenter {\n text-align: center;\n}\n\n.emptyRow {\n padding: var(--tempest-space-6);\n text-align: center;\n color: var(--tempest-text-muted);\n}\n\n/* ============================================================\n * Priority columns — hide below the corresponding breakpoint.\n * ============================================================ */\n@media (max-width: 767.98px) {\n .priorityTablet {\n display: none;\n }\n}\n\n@media (max-width: 1023.98px) {\n .priorityDesktop {\n display: none;\n }\n}\n\n/* ============================================================\n * Stack on mobile — convert rows to label/value cards below md.\n * ============================================================ */\n@media (max-width: 767.98px) {\n .stackable {\n border: 0;\n background: transparent;\n box-shadow: none;\n overflow-x: visible;\n }\n .stackable .table {\n display: block;\n width: 100%;\n }\n .stackableHead {\n position: absolute;\n width: 1px;\n height: 1px;\n overflow: hidden;\n clip: rect(0 0 0 0);\n clip-path: inset(50%);\n white-space: nowrap;\n }\n .stackable tbody,\n .stackable tbody tr,\n .stackable tbody td {\n display: block;\n width: 100%;\n }\n .stackableRow {\n margin-bottom: var(--tempest-space-3);\n border: 1px solid var(--tempest-border);\n border-radius: var(--tempest-radius-lg);\n background-color: var(--tempest-bg);\n box-shadow: var(--tempest-shadow-xs);\n overflow: hidden;\n }\n .stackableRow .td {\n display: flex;\n align-items: center;\n justify-content: space-between;\n gap: var(--tempest-space-3);\n padding: var(--tempest-space-3) var(--tempest-space-4);\n border-bottom: 1px solid var(--tempest-border);\n text-align: left !important;\n }\n .stackableRow .td:last-child {\n border-bottom: none;\n }\n .stackableRow .td::before {\n content: attr(data-label);\n font-size: var(--tempest-text-xs);\n font-weight: var(--tempest-weight-semibold);\n color: var(--tempest-text-muted);\n text-transform: uppercase;\n letter-spacing: var(--tempest-tracking-wider);\n flex-shrink: 0;\n }\n .stackableRow .td:empty::before,\n .stackableRow .td:not([data-label])::before {\n display: none;\n }\n}\n"],"mappings":""}
|
|
1
|
+
{"version":3,"file":"Table.module.cjs","names":[],"sources":["../../../src/components/Table/Table.module.css"],"sourcesContent":[".scroll {\n width: 100%;\n overflow-x: auto;\n border: 1px solid var(--tempest-border);\n border-radius: var(--tempest-radius-lg);\n background-color: var(--tempest-bg);\n box-shadow: var(--tempest-shadow-xs);\n}\n\n.table {\n width: 100%;\n border-collapse: collapse;\n font-family: var(--tempest-font-sans);\n font-size: var(--tempest-text-base);\n line-height: var(--tempest-leading-snug);\n}\n\n.th,\n.td {\n padding: var(--tempest-space-3) var(--tempest-space-4);\n text-align: left;\n border-bottom: 1px solid var(--tempest-border);\n}\n\n.th {\n background-color: var(--tempest-surface);\n color: var(--tempest-text-muted);\n font-weight: var(--tempest-weight-semibold);\n font-size: var(--tempest-text-xs);\n letter-spacing: var(--tempest-tracking-wider);\n text-transform: uppercase;\n white-space: nowrap;\n}\n\n.tr:last-child .td {\n border-bottom: none;\n}\n\n.tr.clickable {\n cursor: pointer;\n transition: background-color var(--tempest-duration-fast) var(--tempest-ease-out);\n}\n\n@media (hover: hover) and (pointer: fine) {\n .tr.clickable:hover {\n background-color: var(--tempest-surface);\n }\n}\n\n.tr.clickable:focus-visible {\n outline: var(--tempest-focus-ring-width) solid var(--tempest-focus-ring-color);\n outline-offset: -2px;\n}\n\n.scroll:focus-visible {\n outline: var(--tempest-focus-ring-width) solid var(--tempest-focus-ring-color);\n outline-offset: 2px;\n}\n\n.alignRight {\n text-align: right;\n}\n\n.alignCenter {\n text-align: center;\n}\n\n.emptyRow {\n padding: var(--tempest-space-6);\n text-align: center;\n color: var(--tempest-text-muted);\n}\n\n/* ============================================================\n * Priority columns — hide below the corresponding breakpoint.\n * ============================================================ */\n@media (max-width: 767.98px) {\n .priorityTablet {\n display: none;\n }\n}\n\n@media (max-width: 1023.98px) {\n .priorityDesktop {\n display: none;\n }\n}\n\n/* ============================================================\n * Stack on mobile — convert rows to label/value cards below md.\n * ============================================================ */\n@media (max-width: 767.98px) {\n .stackable {\n border: 0;\n background: transparent;\n box-shadow: none;\n overflow-x: visible;\n }\n .stackable .table {\n display: block;\n width: 100%;\n }\n .stackableHead {\n position: absolute;\n width: 1px;\n height: 1px;\n overflow: hidden;\n clip: rect(0 0 0 0);\n clip-path: inset(50%);\n white-space: nowrap;\n }\n .stackable tbody,\n .stackable tbody tr,\n .stackable tbody td {\n display: block;\n width: 100%;\n }\n .stackableRow {\n margin-bottom: var(--tempest-space-3);\n border: 1px solid var(--tempest-border);\n border-radius: var(--tempest-radius-lg);\n background-color: var(--tempest-bg);\n box-shadow: var(--tempest-shadow-xs);\n overflow: hidden;\n }\n .stackableRow .td {\n display: flex;\n align-items: center;\n justify-content: space-between;\n gap: var(--tempest-space-3);\n padding: var(--tempest-space-3) var(--tempest-space-4);\n border-bottom: 1px solid var(--tempest-border);\n text-align: left !important;\n }\n .stackableRow .td:last-child {\n border-bottom: none;\n }\n .stackableRow .td::before {\n content: attr(data-label);\n font-size: var(--tempest-text-xs);\n font-weight: var(--tempest-weight-semibold);\n color: var(--tempest-text-muted);\n text-transform: uppercase;\n letter-spacing: var(--tempest-tracking-wider);\n flex-shrink: 0;\n }\n .stackableRow .td:empty::before,\n .stackableRow .td:not([data-label])::before {\n display: none;\n }\n}\n"],"mappings":""}
|
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"Table.module.js","names":[],"sources":["../../../src/components/Table/Table.module.css"],"sourcesContent":[".scroll {\n width: 100%;\n overflow-x: auto;\n border: 1px solid var(--tempest-border);\n border-radius: var(--tempest-radius-lg);\n background-color: var(--tempest-bg);\n box-shadow: var(--tempest-shadow-xs);\n}\n\n.table {\n width: 100%;\n border-collapse: collapse;\n font-family: var(--tempest-font-sans);\n font-size: var(--tempest-text-base);\n line-height: var(--tempest-leading-snug);\n}\n\n.th,\n.td {\n padding: var(--tempest-space-3) var(--tempest-space-4);\n text-align: left;\n border-bottom: 1px solid var(--tempest-border);\n}\n\n.th {\n background-color: var(--tempest-surface);\n color: var(--tempest-text-muted);\n font-weight: var(--tempest-weight-semibold);\n font-size: var(--tempest-text-xs);\n letter-spacing: var(--tempest-tracking-wider);\n text-transform: uppercase;\n white-space: nowrap;\n}\n\n.tr:last-child .td {\n border-bottom: none;\n}\n\n.tr.clickable {\n cursor: pointer;\n transition: background-color var(--tempest-duration-fast) var(--tempest-ease-out);\n}\n\n@media (hover: hover) and (pointer: fine) {\n .tr.clickable:hover {\n background-color: var(--tempest-surface);\n }\n}\n\n.tr.clickable:focus-visible {\n outline: var(--tempest-focus-ring-width) solid var(--tempest-focus-ring-color);\n outline-offset: -2px;\n}\n\n.alignRight {\n text-align: right;\n}\n\n.alignCenter {\n text-align: center;\n}\n\n.emptyRow {\n padding: var(--tempest-space-6);\n text-align: center;\n color: var(--tempest-text-muted);\n}\n\n/* ============================================================\n * Priority columns — hide below the corresponding breakpoint.\n * ============================================================ */\n@media (max-width: 767.98px) {\n .priorityTablet {\n display: none;\n }\n}\n\n@media (max-width: 1023.98px) {\n .priorityDesktop {\n display: none;\n }\n}\n\n/* ============================================================\n * Stack on mobile — convert rows to label/value cards below md.\n * ============================================================ */\n@media (max-width: 767.98px) {\n .stackable {\n border: 0;\n background: transparent;\n box-shadow: none;\n overflow-x: visible;\n }\n .stackable .table {\n display: block;\n width: 100%;\n }\n .stackableHead {\n position: absolute;\n width: 1px;\n height: 1px;\n overflow: hidden;\n clip: rect(0 0 0 0);\n clip-path: inset(50%);\n white-space: nowrap;\n }\n .stackable tbody,\n .stackable tbody tr,\n .stackable tbody td {\n display: block;\n width: 100%;\n }\n .stackableRow {\n margin-bottom: var(--tempest-space-3);\n border: 1px solid var(--tempest-border);\n border-radius: var(--tempest-radius-lg);\n background-color: var(--tempest-bg);\n box-shadow: var(--tempest-shadow-xs);\n overflow: hidden;\n }\n .stackableRow .td {\n display: flex;\n align-items: center;\n justify-content: space-between;\n gap: var(--tempest-space-3);\n padding: var(--tempest-space-3) var(--tempest-space-4);\n border-bottom: 1px solid var(--tempest-border);\n text-align: left !important;\n }\n .stackableRow .td:last-child {\n border-bottom: none;\n }\n .stackableRow .td::before {\n content: attr(data-label);\n font-size: var(--tempest-text-xs);\n font-weight: var(--tempest-weight-semibold);\n color: var(--tempest-text-muted);\n text-transform: uppercase;\n letter-spacing: var(--tempest-tracking-wider);\n flex-shrink: 0;\n }\n .stackableRow .td:empty::before,\n .stackableRow .td:not([data-label])::before {\n display: none;\n }\n}\n"],"mappings":""}
|
|
1
|
+
{"version":3,"file":"Table.module.js","names":[],"sources":["../../../src/components/Table/Table.module.css"],"sourcesContent":[".scroll {\n width: 100%;\n overflow-x: auto;\n border: 1px solid var(--tempest-border);\n border-radius: var(--tempest-radius-lg);\n background-color: var(--tempest-bg);\n box-shadow: var(--tempest-shadow-xs);\n}\n\n.table {\n width: 100%;\n border-collapse: collapse;\n font-family: var(--tempest-font-sans);\n font-size: var(--tempest-text-base);\n line-height: var(--tempest-leading-snug);\n}\n\n.th,\n.td {\n padding: var(--tempest-space-3) var(--tempest-space-4);\n text-align: left;\n border-bottom: 1px solid var(--tempest-border);\n}\n\n.th {\n background-color: var(--tempest-surface);\n color: var(--tempest-text-muted);\n font-weight: var(--tempest-weight-semibold);\n font-size: var(--tempest-text-xs);\n letter-spacing: var(--tempest-tracking-wider);\n text-transform: uppercase;\n white-space: nowrap;\n}\n\n.tr:last-child .td {\n border-bottom: none;\n}\n\n.tr.clickable {\n cursor: pointer;\n transition: background-color var(--tempest-duration-fast) var(--tempest-ease-out);\n}\n\n@media (hover: hover) and (pointer: fine) {\n .tr.clickable:hover {\n background-color: var(--tempest-surface);\n }\n}\n\n.tr.clickable:focus-visible {\n outline: var(--tempest-focus-ring-width) solid var(--tempest-focus-ring-color);\n outline-offset: -2px;\n}\n\n.scroll:focus-visible {\n outline: var(--tempest-focus-ring-width) solid var(--tempest-focus-ring-color);\n outline-offset: 2px;\n}\n\n.alignRight {\n text-align: right;\n}\n\n.alignCenter {\n text-align: center;\n}\n\n.emptyRow {\n padding: var(--tempest-space-6);\n text-align: center;\n color: var(--tempest-text-muted);\n}\n\n/* ============================================================\n * Priority columns — hide below the corresponding breakpoint.\n * ============================================================ */\n@media (max-width: 767.98px) {\n .priorityTablet {\n display: none;\n }\n}\n\n@media (max-width: 1023.98px) {\n .priorityDesktop {\n display: none;\n }\n}\n\n/* ============================================================\n * Stack on mobile — convert rows to label/value cards below md.\n * ============================================================ */\n@media (max-width: 767.98px) {\n .stackable {\n border: 0;\n background: transparent;\n box-shadow: none;\n overflow-x: visible;\n }\n .stackable .table {\n display: block;\n width: 100%;\n }\n .stackableHead {\n position: absolute;\n width: 1px;\n height: 1px;\n overflow: hidden;\n clip: rect(0 0 0 0);\n clip-path: inset(50%);\n white-space: nowrap;\n }\n .stackable tbody,\n .stackable tbody tr,\n .stackable tbody td {\n display: block;\n width: 100%;\n }\n .stackableRow {\n margin-bottom: var(--tempest-space-3);\n border: 1px solid var(--tempest-border);\n border-radius: var(--tempest-radius-lg);\n background-color: var(--tempest-bg);\n box-shadow: var(--tempest-shadow-xs);\n overflow: hidden;\n }\n .stackableRow .td {\n display: flex;\n align-items: center;\n justify-content: space-between;\n gap: var(--tempest-space-3);\n padding: var(--tempest-space-3) var(--tempest-space-4);\n border-bottom: 1px solid var(--tempest-border);\n text-align: left !important;\n }\n .stackableRow .td:last-child {\n border-bottom: none;\n }\n .stackableRow .td::before {\n content: attr(data-label);\n font-size: var(--tempest-text-xs);\n font-weight: var(--tempest-weight-semibold);\n color: var(--tempest-text-muted);\n text-transform: uppercase;\n letter-spacing: var(--tempest-tracking-wider);\n flex-shrink: 0;\n }\n .stackableRow .td:empty::before,\n .stackableRow .td:not([data-label])::before {\n display: none;\n }\n}\n"],"mappings":""}
|
|
@@ -1,2 +1,2 @@
|
|
|
1
|
-
const e=require("../../utils/cn.cjs"),t=require("./VirtualList.module.cjs");let n=require("react"),r=require("react/jsx-runtime");function i({items:i,itemHeight:a,renderItem:o,height:s,overscan:c=4,getKey:l,className:u,style:d}){let
|
|
1
|
+
const e=require("../../utils/cn.cjs"),t=require("./VirtualList.module.cjs");let n=require("react"),r=require("react/jsx-runtime");function i({items:i,itemHeight:a,renderItem:o,height:s,overscan:c=4,getKey:l,className:u,style:d,label:f}){let p=(0,n.useRef)(null),[m,h]=(0,n.useState)(0),[g,_]=(0,n.useState)(0);(0,n.useEffect)(()=>{let e=p.current;if(!e||(_(e.clientHeight),typeof ResizeObserver>`u`))return;let t=new ResizeObserver(()=>_(e.clientHeight));return t.observe(e),()=>t.disconnect()},[]);let v=i.length*a,y=g>0&&v-g>1,b=Math.max(0,Math.floor(m/a)-c),x=Math.ceil(g/a)+c*2,S=Math.min(i.length,b+x);return(0,r.jsx)(`div`,{ref:p,className:e.cn(t.default.scroll,u),style:{height:s,...d},onScroll:e=>h(e.target.scrollTop),role:`list`,"aria-label":f,tabIndex:y?0:void 0,children:(0,r.jsx)(`div`,{className:t.default.spacer,style:{height:v},children:i.slice(b,S).map((e,n)=>{let i=b+n,s=l?l(e,i):i;return(0,r.jsx)(`div`,{role:`listitem`,className:t.default.row,style:{top:i*a,height:a},children:o(e,i)},s)})})})}exports.VirtualList=i;
|
|
2
2
|
//# sourceMappingURL=VirtualList.cjs.map
|
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"VirtualList.cjs","names":[],"sources":["../../../src/components/VirtualList/VirtualList.tsx"],"sourcesContent":["import { useEffect, useRef, useState } from \"react\";\nimport type { CSSProperties, ReactNode } from \"react\";\nimport { cn } from \"@/utils/cn\";\nimport styles from \"./VirtualList.module.css\";\n\nexport interface VirtualListProps<T> {\n items: T[];\n /** Fixed pixel height for each row. */\n itemHeight: number;\n /** Render a single row. */\n renderItem: (item: T, index: number) => ReactNode;\n /** Container height (px) or any CSS length. */\n height: number | string;\n /** Number of items rendered above/below the viewport. Default: 4. */\n overscan?: number;\n /** Stable key derivation; defaults to the index. */\n getKey?: (item: T, index: number) => string | number;\n className?: string;\n style?: CSSProperties;\n}\n\n/**\n * Fixed-height virtual list. Renders only the visible window plus a small\n * overscan buffer. Suitable for lists of thousands of identical rows.\n *\n * For variable heights, use `react-window`/`@tanstack/react-virtual` — those\n * solve a more general problem at the cost of extra setup.\n */\nexport function VirtualList<T>({\n items,\n itemHeight,\n renderItem,\n height,\n overscan = 4,\n getKey,\n className,\n style,\n}: VirtualListProps<T>) {\n const containerRef = useRef<HTMLDivElement>(null);\n const [scrollTop, setScrollTop] = useState<number>(0);\n const [viewport, setViewport] = useState<number>(0);\n\n useEffect(() => {\n const element = containerRef.current;\n if (!element) return;\n setViewport(element.clientHeight);\n if (typeof ResizeObserver === \"undefined\") return;\n const observer = new ResizeObserver(() => setViewport(element.clientHeight));\n observer.observe(element);\n return () => observer.disconnect();\n }, []);\n\n const totalHeight = items.length * itemHeight;\n const start = Math.max(0, Math.floor(scrollTop / itemHeight) - overscan);\n const visibleCount = Math.ceil(viewport / itemHeight) + overscan * 2;\n const end = Math.min(items.length, start + visibleCount);\n\n return (\n <div\n ref={containerRef}\n className={cn(styles.scroll, className)}\n style={{ height, ...style }}\n onScroll={(event) => setScrollTop((event.target as HTMLDivElement).scrollTop)}\n role=\"list\"\n >\n <div className={styles.spacer} style={{ height: totalHeight }}>\n {items.slice(start, end).map((item, offset) => {\n const index = start + offset;\n const key = getKey ? getKey(item, index) : index;\n return (\n <div\n key={key}\n role=\"listitem\"\n className={styles.row}\n style={{ top: index * itemHeight, height: itemHeight }}\n >\n {renderItem(item, index)}\n </div>\n );\n })}\n </div>\n </div>\n );\n}\n"],"mappings":"
|
|
1
|
+
{"version":3,"file":"VirtualList.cjs","names":[],"sources":["../../../src/components/VirtualList/VirtualList.tsx"],"sourcesContent":["import { useEffect, useRef, useState } from \"react\";\nimport type { CSSProperties, ReactNode } from \"react\";\nimport { cn } from \"@/utils/cn\";\nimport styles from \"./VirtualList.module.css\";\n\nexport interface VirtualListProps<T> {\n items: T[];\n /** Fixed pixel height for each row. */\n itemHeight: number;\n /** Render a single row. */\n renderItem: (item: T, index: number) => ReactNode;\n /** Container height (px) or any CSS length. */\n height: number | string;\n /** Number of items rendered above/below the viewport. Default: 4. */\n overscan?: number;\n /** Stable key derivation; defaults to the index. */\n getKey?: (item: T, index: number) => string | number;\n className?: string;\n style?: CSSProperties;\n /**\n * Accessible name for the list. Worth setting when the list scrolls: it\n * then carries a tab stop of its own, and a focus stop that announces\n * nothing is worse than no focus stop.\n */\n label?: string;\n}\n\n/**\n * Fixed-height virtual list. Renders only the visible window plus a small\n * overscan buffer. Suitable for lists of thousands of identical rows.\n *\n * For variable heights, use `react-window`/`@tanstack/react-virtual` — those\n * solve a more general problem at the cost of extra setup.\n */\nexport function VirtualList<T>({\n items,\n itemHeight,\n renderItem,\n height,\n overscan = 4,\n getKey,\n className,\n style,\n label,\n}: VirtualListProps<T>) {\n const containerRef = useRef<HTMLDivElement>(null);\n const [scrollTop, setScrollTop] = useState<number>(0);\n const [viewport, setViewport] = useState<number>(0);\n\n useEffect(() => {\n const element = containerRef.current;\n if (!element) return;\n setViewport(element.clientHeight);\n if (typeof ResizeObserver === \"undefined\") return;\n const observer = new ResizeObserver(() => setViewport(element.clientHeight));\n observer.observe(element);\n return () => observer.disconnect();\n }, []);\n\n const totalHeight = items.length * itemHeight;\n /*\n * Rows are absolutely positioned inside the spacer, so nothing in a\n * virtual list is focusable by default: a keyboard user can see the\n * scrollbar and has no way to move it. The tab stop only appears while\n * there is something past the fold — measured from the numbers already at\n * hand rather than from the DOM.\n */\n const scrollable = viewport > 0 && totalHeight - viewport > 1;\n const start = Math.max(0, Math.floor(scrollTop / itemHeight) - overscan);\n const visibleCount = Math.ceil(viewport / itemHeight) + overscan * 2;\n const end = Math.min(items.length, start + visibleCount);\n\n return (\n <div\n ref={containerRef}\n className={cn(styles.scroll, className)}\n style={{ height, ...style }}\n onScroll={(event) => setScrollTop((event.target as HTMLDivElement).scrollTop)}\n role=\"list\"\n aria-label={label}\n tabIndex={scrollable ? 0 : undefined}\n >\n <div className={styles.spacer} style={{ height: totalHeight }}>\n {items.slice(start, end).map((item, offset) => {\n const index = start + offset;\n const key = getKey ? getKey(item, index) : index;\n return (\n <div\n key={key}\n role=\"listitem\"\n className={styles.row}\n style={{ top: index * itemHeight, height: itemHeight }}\n >\n {renderItem(item, index)}\n </div>\n );\n })}\n </div>\n </div>\n );\n}\n"],"mappings":"kIAkCA,SAAgB,EAAe,CAC3B,QACA,aACA,aACA,SACA,WAAW,EACX,SACA,YACA,QACA,SACoB,CACpB,IAAM,GAAA,EAAA,EAAA,OAAA,CAAsC,IAAI,EAC1C,CAAC,EAAW,IAAA,EAAA,EAAA,SAAA,CAAiC,CAAC,EAC9C,CAAC,EAAU,IAAA,EAAA,EAAA,SAAA,CAAgC,CAAC,GAElD,EAAA,EAAA,UAAA,KAAgB,CACZ,IAAM,EAAU,EAAa,QAG7B,GAFI,CAAC,IACL,EAAY,EAAQ,YAAY,EAC5B,OAAO,eAAmB,KAAa,OAC3C,IAAM,EAAW,IAAI,mBAAqB,EAAY,EAAQ,YAAY,CAAC,EAE3E,OADA,EAAS,QAAQ,CAAO,MACX,EAAS,WAAW,CACrC,EAAG,CAAC,CAAC,EAEL,IAAM,EAAc,EAAM,OAAS,EAQ7B,EAAa,EAAW,GAAK,EAAc,EAAW,EACtD,EAAQ,KAAK,IAAI,EAAG,KAAK,MAAM,EAAY,CAAU,EAAI,CAAQ,EACjE,EAAe,KAAK,KAAK,EAAW,CAAU,EAAI,EAAW,EAC7D,EAAM,KAAK,IAAI,EAAM,OAAQ,EAAQ,CAAY,EAEvD,OACI,EAAA,EAAA,IAAA,CAAC,MAAD,CACI,IAAK,EACL,UAAW,EAAA,GAAG,EAAA,QAAO,OAAQ,CAAS,EACtC,MAAO,CAAE,SAAQ,GAAG,CAAM,EAC1B,SAAW,GAAU,EAAc,EAAM,OAA0B,SAAS,EAC5E,KAAK,OACL,aAAY,EACZ,SAAU,EAAa,EAAI,IAAA,aAE3B,EAAA,EAAA,IAAA,CAAC,MAAD,CAAK,UAAW,EAAA,QAAO,OAAQ,MAAO,CAAE,OAAQ,CAAY,WACvD,EAAM,MAAM,EAAO,CAAG,CAAC,CAAC,KAAK,EAAM,IAAW,CAC3C,IAAM,EAAQ,EAAQ,EAChB,EAAM,EAAS,EAAO,EAAM,CAAK,EAAI,EAC3C,OACI,EAAA,EAAA,IAAA,CAAC,MAAD,CAEI,KAAK,WACL,UAAW,EAAA,QAAO,IAClB,MAAO,CAAE,IAAK,EAAQ,EAAY,OAAQ,CAAW,WAEpD,EAAW,EAAM,CAAK,CACtB,EANI,CAMJ,CAEb,CAAC,CACA,CAAA,CACJ,CAAA,CAEb"}
|
|
@@ -3,29 +3,31 @@ import t from "./VirtualList.module.js";
|
|
|
3
3
|
import { useEffect as n, useRef as r, useState as i } from "react";
|
|
4
4
|
import { jsx as a } from "react/jsx-runtime";
|
|
5
5
|
//#region src/components/VirtualList/VirtualList.tsx
|
|
6
|
-
function o({ items: o, itemHeight: s, renderItem: c, height: l, overscan: u = 4, getKey: d, className: f, style: p }) {
|
|
7
|
-
let
|
|
6
|
+
function o({ items: o, itemHeight: s, renderItem: c, height: l, overscan: u = 4, getKey: d, className: f, style: p, label: m }) {
|
|
7
|
+
let h = r(null), [g, _] = i(0), [v, y] = i(0);
|
|
8
8
|
n(() => {
|
|
9
|
-
let e =
|
|
10
|
-
if (!e || (
|
|
11
|
-
let t = new ResizeObserver(() =>
|
|
9
|
+
let e = h.current;
|
|
10
|
+
if (!e || (y(e.clientHeight), typeof ResizeObserver > "u")) return;
|
|
11
|
+
let t = new ResizeObserver(() => y(e.clientHeight));
|
|
12
12
|
return t.observe(e), () => t.disconnect();
|
|
13
13
|
}, []);
|
|
14
|
-
let
|
|
14
|
+
let b = o.length * s, x = v > 0 && b - v > 1, S = Math.max(0, Math.floor(g / s) - u), C = Math.ceil(v / s) + u * 2, w = Math.min(o.length, S + C);
|
|
15
15
|
return /* @__PURE__ */ a("div", {
|
|
16
|
-
ref:
|
|
16
|
+
ref: h,
|
|
17
17
|
className: e(t.scroll, f),
|
|
18
18
|
style: {
|
|
19
19
|
height: l,
|
|
20
20
|
...p
|
|
21
21
|
},
|
|
22
|
-
onScroll: (e) =>
|
|
22
|
+
onScroll: (e) => _(e.target.scrollTop),
|
|
23
23
|
role: "list",
|
|
24
|
+
"aria-label": m,
|
|
25
|
+
tabIndex: x ? 0 : void 0,
|
|
24
26
|
children: /* @__PURE__ */ a("div", {
|
|
25
27
|
className: t.spacer,
|
|
26
|
-
style: { height:
|
|
27
|
-
children: o.slice(
|
|
28
|
-
let r =
|
|
28
|
+
style: { height: b },
|
|
29
|
+
children: o.slice(S, w).map((e, n) => {
|
|
30
|
+
let r = S + n, i = d ? d(e, r) : r;
|
|
29
31
|
return /* @__PURE__ */ a("div", {
|
|
30
32
|
role: "listitem",
|
|
31
33
|
className: t.row,
|
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"VirtualList.js","names":[],"sources":["../../../src/components/VirtualList/VirtualList.tsx"],"sourcesContent":["import { useEffect, useRef, useState } from \"react\";\nimport type { CSSProperties, ReactNode } from \"react\";\nimport { cn } from \"@/utils/cn\";\nimport styles from \"./VirtualList.module.css\";\n\nexport interface VirtualListProps<T> {\n items: T[];\n /** Fixed pixel height for each row. */\n itemHeight: number;\n /** Render a single row. */\n renderItem: (item: T, index: number) => ReactNode;\n /** Container height (px) or any CSS length. */\n height: number | string;\n /** Number of items rendered above/below the viewport. Default: 4. */\n overscan?: number;\n /** Stable key derivation; defaults to the index. */\n getKey?: (item: T, index: number) => string | number;\n className?: string;\n style?: CSSProperties;\n}\n\n/**\n * Fixed-height virtual list. Renders only the visible window plus a small\n * overscan buffer. Suitable for lists of thousands of identical rows.\n *\n * For variable heights, use `react-window`/`@tanstack/react-virtual` — those\n * solve a more general problem at the cost of extra setup.\n */\nexport function VirtualList<T>({\n items,\n itemHeight,\n renderItem,\n height,\n overscan = 4,\n getKey,\n className,\n style,\n}: VirtualListProps<T>) {\n const containerRef = useRef<HTMLDivElement>(null);\n const [scrollTop, setScrollTop] = useState<number>(0);\n const [viewport, setViewport] = useState<number>(0);\n\n useEffect(() => {\n const element = containerRef.current;\n if (!element) return;\n setViewport(element.clientHeight);\n if (typeof ResizeObserver === \"undefined\") return;\n const observer = new ResizeObserver(() => setViewport(element.clientHeight));\n observer.observe(element);\n return () => observer.disconnect();\n }, []);\n\n const totalHeight = items.length * itemHeight;\n const start = Math.max(0, Math.floor(scrollTop / itemHeight) - overscan);\n const visibleCount = Math.ceil(viewport / itemHeight) + overscan * 2;\n const end = Math.min(items.length, start + visibleCount);\n\n return (\n <div\n ref={containerRef}\n className={cn(styles.scroll, className)}\n style={{ height, ...style }}\n onScroll={(event) => setScrollTop((event.target as HTMLDivElement).scrollTop)}\n role=\"list\"\n >\n <div className={styles.spacer} style={{ height: totalHeight }}>\n {items.slice(start, end).map((item, offset) => {\n const index = start + offset;\n const key = getKey ? getKey(item, index) : index;\n return (\n <div\n key={key}\n role=\"listitem\"\n className={styles.row}\n style={{ top: index * itemHeight, height: itemHeight }}\n >\n {renderItem(item, index)}\n </div>\n );\n })}\n </div>\n </div>\n );\n}\n"],"mappings":";;;;;
|
|
1
|
+
{"version":3,"file":"VirtualList.js","names":[],"sources":["../../../src/components/VirtualList/VirtualList.tsx"],"sourcesContent":["import { useEffect, useRef, useState } from \"react\";\nimport type { CSSProperties, ReactNode } from \"react\";\nimport { cn } from \"@/utils/cn\";\nimport styles from \"./VirtualList.module.css\";\n\nexport interface VirtualListProps<T> {\n items: T[];\n /** Fixed pixel height for each row. */\n itemHeight: number;\n /** Render a single row. */\n renderItem: (item: T, index: number) => ReactNode;\n /** Container height (px) or any CSS length. */\n height: number | string;\n /** Number of items rendered above/below the viewport. Default: 4. */\n overscan?: number;\n /** Stable key derivation; defaults to the index. */\n getKey?: (item: T, index: number) => string | number;\n className?: string;\n style?: CSSProperties;\n /**\n * Accessible name for the list. Worth setting when the list scrolls: it\n * then carries a tab stop of its own, and a focus stop that announces\n * nothing is worse than no focus stop.\n */\n label?: string;\n}\n\n/**\n * Fixed-height virtual list. Renders only the visible window plus a small\n * overscan buffer. Suitable for lists of thousands of identical rows.\n *\n * For variable heights, use `react-window`/`@tanstack/react-virtual` — those\n * solve a more general problem at the cost of extra setup.\n */\nexport function VirtualList<T>({\n items,\n itemHeight,\n renderItem,\n height,\n overscan = 4,\n getKey,\n className,\n style,\n label,\n}: VirtualListProps<T>) {\n const containerRef = useRef<HTMLDivElement>(null);\n const [scrollTop, setScrollTop] = useState<number>(0);\n const [viewport, setViewport] = useState<number>(0);\n\n useEffect(() => {\n const element = containerRef.current;\n if (!element) return;\n setViewport(element.clientHeight);\n if (typeof ResizeObserver === \"undefined\") return;\n const observer = new ResizeObserver(() => setViewport(element.clientHeight));\n observer.observe(element);\n return () => observer.disconnect();\n }, []);\n\n const totalHeight = items.length * itemHeight;\n /*\n * Rows are absolutely positioned inside the spacer, so nothing in a\n * virtual list is focusable by default: a keyboard user can see the\n * scrollbar and has no way to move it. The tab stop only appears while\n * there is something past the fold — measured from the numbers already at\n * hand rather than from the DOM.\n */\n const scrollable = viewport > 0 && totalHeight - viewport > 1;\n const start = Math.max(0, Math.floor(scrollTop / itemHeight) - overscan);\n const visibleCount = Math.ceil(viewport / itemHeight) + overscan * 2;\n const end = Math.min(items.length, start + visibleCount);\n\n return (\n <div\n ref={containerRef}\n className={cn(styles.scroll, className)}\n style={{ height, ...style }}\n onScroll={(event) => setScrollTop((event.target as HTMLDivElement).scrollTop)}\n role=\"list\"\n aria-label={label}\n tabIndex={scrollable ? 0 : undefined}\n >\n <div className={styles.spacer} style={{ height: totalHeight }}>\n {items.slice(start, end).map((item, offset) => {\n const index = start + offset;\n const key = getKey ? getKey(item, index) : index;\n return (\n <div\n key={key}\n role=\"listitem\"\n className={styles.row}\n style={{ top: index * itemHeight, height: itemHeight }}\n >\n {renderItem(item, index)}\n </div>\n );\n })}\n </div>\n </div>\n );\n}\n"],"mappings":";;;;;AAkCA,SAAgB,EAAe,EAC3B,UACA,eACA,eACA,WACA,cAAW,GACX,WACA,cACA,UACA,YACoB;CACpB,IAAM,IAAe,EAAuB,IAAI,GAC1C,CAAC,GAAW,KAAgB,EAAiB,CAAC,GAC9C,CAAC,GAAU,KAAe,EAAiB,CAAC;CAElD,QAAgB;EACZ,IAAM,IAAU,EAAa;EAG7B,IAFI,CAAC,MACL,EAAY,EAAQ,YAAY,GAC5B,OAAO,iBAAmB,MAAa;EAC3C,IAAM,IAAW,IAAI,qBAAqB,EAAY,EAAQ,YAAY,CAAC;EAE3E,OADA,EAAS,QAAQ,CAAO,SACX,EAAS,WAAW;CACrC,GAAG,CAAC,CAAC;CAEL,IAAM,IAAc,EAAM,SAAS,GAQ7B,IAAa,IAAW,KAAK,IAAc,IAAW,GACtD,IAAQ,KAAK,IAAI,GAAG,KAAK,MAAM,IAAY,CAAU,IAAI,CAAQ,GACjE,IAAe,KAAK,KAAK,IAAW,CAAU,IAAI,IAAW,GAC7D,IAAM,KAAK,IAAI,EAAM,QAAQ,IAAQ,CAAY;CAEvD,OACI,kBAAC,OAAD;EACI,KAAK;EACL,WAAW,EAAG,EAAO,QAAQ,CAAS;EACtC,OAAO;GAAE;GAAQ,GAAG;EAAM;EAC1B,WAAW,MAAU,EAAc,EAAM,OAA0B,SAAS;EAC5E,MAAK;EACL,cAAY;EACZ,UAAU,IAAa,IAAI,KAAA;YAE3B,kBAAC,OAAD;GAAK,WAAW,EAAO;GAAQ,OAAO,EAAE,QAAQ,EAAY;aACvD,EAAM,MAAM,GAAO,CAAG,CAAC,CAAC,KAAK,GAAM,MAAW;IAC3C,IAAM,IAAQ,IAAQ,GAChB,IAAM,IAAS,EAAO,GAAM,CAAK,IAAI;IAC3C,OACI,kBAAC,OAAD;KAEI,MAAK;KACL,WAAW,EAAO;KAClB,OAAO;MAAE,KAAK,IAAQ;MAAY,QAAQ;KAAW;eAEpD,EAAW,GAAM,CAAK;IACtB,GANI,CAMJ;GAEb,CAAC;EACA,CAAA;CACJ,CAAA;AAEb"}
|
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"VirtualList.module.cjs","names":[],"sources":["../../../src/components/VirtualList/VirtualList.module.css"],"sourcesContent":[".scroll {\n position: relative;\n overflow: auto;\n width: 100%;\n}\n\n.spacer {\n position: relative;\n width: 100%;\n}\n\n.row {\n position: absolute;\n left: 0;\n right: 0;\n}\n"],"mappings":""}
|
|
1
|
+
{"version":3,"file":"VirtualList.module.cjs","names":[],"sources":["../../../src/components/VirtualList/VirtualList.module.css"],"sourcesContent":[".scroll {\n position: relative;\n overflow: auto;\n width: 100%;\n}\n\n.spacer {\n position: relative;\n width: 100%;\n}\n\n.row {\n position: absolute;\n left: 0;\n right: 0;\n}\n\n.scroll:focus-visible {\n outline: var(--tempest-focus-ring-width) solid var(--tempest-focus-ring-color);\n outline-offset: 2px;\n}\n"],"mappings":""}
|
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"VirtualList.module.js","names":[],"sources":["../../../src/components/VirtualList/VirtualList.module.css"],"sourcesContent":[".scroll {\n position: relative;\n overflow: auto;\n width: 100%;\n}\n\n.spacer {\n position: relative;\n width: 100%;\n}\n\n.row {\n position: absolute;\n left: 0;\n right: 0;\n}\n"],"mappings":""}
|
|
1
|
+
{"version":3,"file":"VirtualList.module.js","names":[],"sources":["../../../src/components/VirtualList/VirtualList.module.css"],"sourcesContent":[".scroll {\n position: relative;\n overflow: auto;\n width: 100%;\n}\n\n.spacer {\n position: relative;\n width: 100%;\n}\n\n.row {\n position: absolute;\n left: 0;\n right: 0;\n}\n\n.scroll:focus-visible {\n outline: var(--tempest-focus-ring-width) solid var(--tempest-focus-ring-color);\n outline-offset: 2px;\n}\n"],"mappings":""}
|
|
@@ -0,0 +1,2 @@
|
|
|
1
|
+
let e=require("react");function t(t,n=`both`){let[r,i]=(0,e.useState)(!1);return(0,e.useEffect)(()=>{let e=t.current;if(!e)return;let r=()=>{let t=e.scrollWidth-e.clientWidth>1,r=e.scrollHeight-e.clientHeight>1;i(n===`horizontal`?t:n===`vertical`?r:t||r)};if(r(),typeof ResizeObserver>`u`)return;let a=new ResizeObserver(r);a.observe(e);let o=e.firstElementChild;return o&&a.observe(o),()=>a.disconnect()},[t,n]),r}exports.useScrollOverflow=t;
|
|
2
|
+
//# sourceMappingURL=use-scroll-overflow.cjs.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"use-scroll-overflow.cjs","names":[],"sources":["../../src/hooks/use-scroll-overflow.ts"],"sourcesContent":["import { useEffect, useState } from \"react\";\nimport type { RefObject } from \"react\";\n\n/** Which axis to watch for overflow. */\nexport type ScrollOverflowAxis = \"horizontal\" | \"vertical\" | \"both\";\n\n/**\n * Track whether an element's content currently overflows its box.\n *\n * The use this exists for is keyboard access. A scroll container holding no\n * focusable content is unreachable by keyboard: the user can see there is more\n * content past the edge and has no way to get to it, because focus never lands\n * anywhere the arrow keys would scroll. Giving the container `tabIndex={0}`\n * fixes it — but doing that unconditionally puts a tab stop on every such\n * container on the page, including the ones whose content fits and have nothing\n * to scroll. The stop is only wanted while the overflow is real, which is what\n * this reports. (It is also what axe checks as `scrollable-region-focusable`.)\n *\n * Both the container and its content are observed: content can outgrow a box\n * whose own dimensions never change, and a box can shrink around content that\n * never changes. Watching one alone misses half the transitions.\n *\n * A one-pixel difference is ignored — that is layout rounding, not overflow.\n *\n * @param ref - The scroll container.\n * @param axis - Which axis to measure. Defaults to `\"both\"`.\n * @returns `true` while the content is larger than the box on that axis.\n *\n * @example\n * const ref = useRef<HTMLDivElement>(null);\n * const scrollable = useScrollOverflow(ref, \"horizontal\");\n *\n * <div\n * ref={ref}\n * tabIndex={scrollable ? 0 : undefined}\n * role={scrollable ? \"group\" : undefined}\n * aria-label={scrollable ? \"Tabela rolável\" : undefined}\n * >\n */\nexport function useScrollOverflow(\n ref: RefObject<HTMLElement | null>,\n axis: ScrollOverflowAxis = \"both\",\n): boolean {\n const [overflowing, setOverflowing] = useState(false);\n\n useEffect(() => {\n const element = ref.current;\n if (!element) return;\n\n const measure = () => {\n const horizontal = element.scrollWidth - element.clientWidth > 1;\n const vertical = element.scrollHeight - element.clientHeight > 1;\n if (axis === \"horizontal\") setOverflowing(horizontal);\n else if (axis === \"vertical\") setOverflowing(vertical);\n else setOverflowing(horizontal || vertical);\n };\n measure();\n\n if (typeof ResizeObserver === \"undefined\") return;\n\n const observer = new ResizeObserver(measure);\n observer.observe(element);\n const content = element.firstElementChild;\n if (content) observer.observe(content);\n return () => observer.disconnect();\n }, [ref, axis]);\n\n return overflowing;\n}\n"],"mappings":"uBAuCA,SAAgB,EACZ,EACA,EAA2B,OACpB,CACP,GAAM,CAAC,EAAa,IAAA,EAAA,EAAA,SAAA,CAA2B,EAAK,EAwBpD,OAtBA,EAAA,EAAA,UAAA,KAAgB,CACZ,IAAM,EAAU,EAAI,QACpB,GAAI,CAAC,EAAS,OAEd,IAAM,MAAgB,CAClB,IAAM,EAAa,EAAQ,YAAc,EAAQ,YAAc,EACzD,EAAW,EAAQ,aAAe,EAAQ,aAAe,EACpC,EAAvB,IAAS,aAA6B,EACjC,IAAS,WAA2B,EACzB,GAAc,CAAQ,CAC9C,EAGA,GAFA,EAAQ,EAEJ,OAAO,eAAmB,IAAa,OAE3C,IAAM,EAAW,IAAI,eAAe,CAAO,EAC3C,EAAS,QAAQ,CAAO,EACxB,IAAM,EAAU,EAAQ,kBAExB,OADI,GAAS,EAAS,QAAQ,CAAO,MACxB,EAAS,WAAW,CACrC,EAAG,CAAC,EAAK,CAAI,CAAC,EAEP,CACX"}
|
|
@@ -0,0 +1,22 @@
|
|
|
1
|
+
import { useEffect as e, useState as t } from "react";
|
|
2
|
+
//#region src/hooks/use-scroll-overflow.ts
|
|
3
|
+
function n(n, r = "both") {
|
|
4
|
+
let [i, a] = t(!1);
|
|
5
|
+
return e(() => {
|
|
6
|
+
let e = n.current;
|
|
7
|
+
if (!e) return;
|
|
8
|
+
let t = () => {
|
|
9
|
+
let t = e.scrollWidth - e.clientWidth > 1, n = e.scrollHeight - e.clientHeight > 1;
|
|
10
|
+
a(r === "horizontal" ? t : r === "vertical" ? n : t || n);
|
|
11
|
+
};
|
|
12
|
+
if (t(), typeof ResizeObserver > "u") return;
|
|
13
|
+
let i = new ResizeObserver(t);
|
|
14
|
+
i.observe(e);
|
|
15
|
+
let o = e.firstElementChild;
|
|
16
|
+
return o && i.observe(o), () => i.disconnect();
|
|
17
|
+
}, [n, r]), i;
|
|
18
|
+
}
|
|
19
|
+
//#endregion
|
|
20
|
+
export { n as useScrollOverflow };
|
|
21
|
+
|
|
22
|
+
//# sourceMappingURL=use-scroll-overflow.js.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"use-scroll-overflow.js","names":[],"sources":["../../src/hooks/use-scroll-overflow.ts"],"sourcesContent":["import { useEffect, useState } from \"react\";\nimport type { RefObject } from \"react\";\n\n/** Which axis to watch for overflow. */\nexport type ScrollOverflowAxis = \"horizontal\" | \"vertical\" | \"both\";\n\n/**\n * Track whether an element's content currently overflows its box.\n *\n * The use this exists for is keyboard access. A scroll container holding no\n * focusable content is unreachable by keyboard: the user can see there is more\n * content past the edge and has no way to get to it, because focus never lands\n * anywhere the arrow keys would scroll. Giving the container `tabIndex={0}`\n * fixes it — but doing that unconditionally puts a tab stop on every such\n * container on the page, including the ones whose content fits and have nothing\n * to scroll. The stop is only wanted while the overflow is real, which is what\n * this reports. (It is also what axe checks as `scrollable-region-focusable`.)\n *\n * Both the container and its content are observed: content can outgrow a box\n * whose own dimensions never change, and a box can shrink around content that\n * never changes. Watching one alone misses half the transitions.\n *\n * A one-pixel difference is ignored — that is layout rounding, not overflow.\n *\n * @param ref - The scroll container.\n * @param axis - Which axis to measure. Defaults to `\"both\"`.\n * @returns `true` while the content is larger than the box on that axis.\n *\n * @example\n * const ref = useRef<HTMLDivElement>(null);\n * const scrollable = useScrollOverflow(ref, \"horizontal\");\n *\n * <div\n * ref={ref}\n * tabIndex={scrollable ? 0 : undefined}\n * role={scrollable ? \"group\" : undefined}\n * aria-label={scrollable ? \"Tabela rolável\" : undefined}\n * >\n */\nexport function useScrollOverflow(\n ref: RefObject<HTMLElement | null>,\n axis: ScrollOverflowAxis = \"both\",\n): boolean {\n const [overflowing, setOverflowing] = useState(false);\n\n useEffect(() => {\n const element = ref.current;\n if (!element) return;\n\n const measure = () => {\n const horizontal = element.scrollWidth - element.clientWidth > 1;\n const vertical = element.scrollHeight - element.clientHeight > 1;\n if (axis === \"horizontal\") setOverflowing(horizontal);\n else if (axis === \"vertical\") setOverflowing(vertical);\n else setOverflowing(horizontal || vertical);\n };\n measure();\n\n if (typeof ResizeObserver === \"undefined\") return;\n\n const observer = new ResizeObserver(measure);\n observer.observe(element);\n const content = element.firstElementChild;\n if (content) observer.observe(content);\n return () => observer.disconnect();\n }, [ref, axis]);\n\n return overflowing;\n}\n"],"mappings":";;AAuCA,SAAgB,EACZ,GACA,IAA2B,QACpB;CACP,IAAM,CAAC,GAAa,KAAkB,EAAS,EAAK;CAwBpD,OAtBA,QAAgB;EACZ,IAAM,IAAU,EAAI;EACpB,IAAI,CAAC,GAAS;EAEd,IAAM,UAAgB;GAClB,IAAM,IAAa,EAAQ,cAAc,EAAQ,cAAc,GACzD,IAAW,EAAQ,eAAe,EAAQ,eAAe;GAC/D,AAA2B,EAAvB,MAAS,eAA6B,IACjC,MAAS,aAA2B,IACzB,KAAc,CAAQ;EAC9C;EAGA,IAFA,EAAQ,GAEJ,OAAO,iBAAmB,KAAa;EAE3C,IAAM,IAAW,IAAI,eAAe,CAAO;EAC3C,EAAS,QAAQ,CAAO;EACxB,IAAM,IAAU,EAAQ;EAExB,OADI,KAAS,EAAS,QAAQ,CAAO,SACxB,EAAS,WAAW;CACrC,GAAG,CAAC,GAAK,CAAI,CAAC,GAEP;AACX"}
|
package/dist/push/utils.cjs
CHANGED
|
@@ -1,2 +1,2 @@
|
|
|
1
|
-
function e(e){let t=(e+`=`.repeat((4-e.length%4)%4)).replace(/-/g,`+`).replace(/_/g,`/`),n=
|
|
1
|
+
function e(e){let t=(e+`=`.repeat((4-e.length%4)%4)).replace(/-/g,`+`).replace(/_/g,`/`),n=atob(t),r=new ArrayBuffer(n.length),i=new Uint8Array(r);for(let e=0;e<n.length;e++)i[e]=n.charCodeAt(e);return i}function t(){return typeof window<`u`&&`serviceWorker`in navigator&&`PushManager`in window&&`Notification`in window}exports.isPushSupported=t,exports.urlBase64ToUint8Array=e;
|
|
2
2
|
//# sourceMappingURL=utils.cjs.map
|
package/dist/push/utils.cjs.map
CHANGED
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"utils.cjs","names":[],"sources":["../../src/push/utils.ts"],"sourcesContent":["/**\n * Convert a base64url-encoded VAPID public key into the `Uint8Array` format\n * required by `PushManager.subscribe({ applicationServerKey })`.\n *\n * @param base64String - VAPID public key (URL-safe base64).\n * @returns The decoded key as bytes.\n */\nexport function urlBase64ToUint8Array(base64String: string): Uint8Array<ArrayBuffer> {\n const padding = \"=\".repeat((4 - (base64String.length % 4)) % 4);\n const base64 = (base64String + padding).replace(/-/g, \"+\").replace(/_/g, \"/\");\n const rawData =
|
|
1
|
+
{"version":3,"file":"utils.cjs","names":[],"sources":["../../src/push/utils.ts"],"sourcesContent":["/**\n * Convert a base64url-encoded VAPID public key into the `Uint8Array` format\n * required by `PushManager.subscribe({ applicationServerKey })`.\n *\n * Calls `atob` as a bare global rather than `window.atob` because this runs in a\n * **service worker** too: re-subscribing from a `pushsubscriptionchange` handler\n * needs the same conversion, and there is no `window` in a worker scope — the\n * qualified call threw `ReferenceError` there while working fine on the page.\n *\n * @param base64String - VAPID public key (URL-safe base64).\n * @returns The decoded key as bytes.\n */\nexport function urlBase64ToUint8Array(base64String: string): Uint8Array<ArrayBuffer> {\n const padding = \"=\".repeat((4 - (base64String.length % 4)) % 4);\n const base64 = (base64String + padding).replace(/-/g, \"+\").replace(/_/g, \"/\");\n const rawData = atob(base64);\n const buffer = new ArrayBuffer(rawData.length);\n const output = new Uint8Array(buffer);\n for (let i = 0; i < rawData.length; i++) {\n output[i] = rawData.charCodeAt(i);\n }\n return output;\n}\n\n/**\n * Convenience check for environments where the Push API is unavailable\n * (Safari iOS without PWA install, older browsers, SSR, etc.).\n */\nexport function isPushSupported(): boolean {\n return (\n typeof window !== \"undefined\" &&\n \"serviceWorker\" in navigator &&\n \"PushManager\" in window &&\n \"Notification\" in window\n );\n}\n"],"mappings":"AAYA,SAAgB,EAAsB,EAA+C,CAEjF,IAAM,GAAU,EADA,IAAI,QAAQ,EAAK,EAAa,OAAS,GAAM,CAC9B,EAAA,CAAS,QAAQ,KAAM,GAAG,CAAC,CAAC,QAAQ,KAAM,GAAG,EACtE,EAAU,KAAK,CAAM,EACrB,EAAS,IAAI,YAAY,EAAQ,MAAM,EACvC,EAAS,IAAI,WAAW,CAAM,EACpC,IAAK,IAAI,EAAI,EAAG,EAAI,EAAQ,OAAQ,IAChC,EAAO,GAAK,EAAQ,WAAW,CAAC,EAEpC,OAAO,CACX,CAMA,SAAgB,GAA2B,CACvC,OACI,OAAO,OAAW,KAClB,kBAAmB,WACnB,gBAAiB,QACjB,iBAAkB,MAE1B"}
|
package/dist/push/utils.js
CHANGED
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
//#region src/push/utils.ts
|
|
2
2
|
function e(e) {
|
|
3
|
-
let t = (e + "=".repeat((4 - e.length % 4) % 4)).replace(/-/g, "+").replace(/_/g, "/"), n =
|
|
3
|
+
let t = (e + "=".repeat((4 - e.length % 4) % 4)).replace(/-/g, "+").replace(/_/g, "/"), n = atob(t), r = new ArrayBuffer(n.length), i = new Uint8Array(r);
|
|
4
4
|
for (let e = 0; e < n.length; e++) i[e] = n.charCodeAt(e);
|
|
5
5
|
return i;
|
|
6
6
|
}
|
package/dist/push/utils.js.map
CHANGED
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"utils.js","names":[],"sources":["../../src/push/utils.ts"],"sourcesContent":["/**\n * Convert a base64url-encoded VAPID public key into the `Uint8Array` format\n * required by `PushManager.subscribe({ applicationServerKey })`.\n *\n * @param base64String - VAPID public key (URL-safe base64).\n * @returns The decoded key as bytes.\n */\nexport function urlBase64ToUint8Array(base64String: string): Uint8Array<ArrayBuffer> {\n const padding = \"=\".repeat((4 - (base64String.length % 4)) % 4);\n const base64 = (base64String + padding).replace(/-/g, \"+\").replace(/_/g, \"/\");\n const rawData =
|
|
1
|
+
{"version":3,"file":"utils.js","names":[],"sources":["../../src/push/utils.ts"],"sourcesContent":["/**\n * Convert a base64url-encoded VAPID public key into the `Uint8Array` format\n * required by `PushManager.subscribe({ applicationServerKey })`.\n *\n * Calls `atob` as a bare global rather than `window.atob` because this runs in a\n * **service worker** too: re-subscribing from a `pushsubscriptionchange` handler\n * needs the same conversion, and there is no `window` in a worker scope — the\n * qualified call threw `ReferenceError` there while working fine on the page.\n *\n * @param base64String - VAPID public key (URL-safe base64).\n * @returns The decoded key as bytes.\n */\nexport function urlBase64ToUint8Array(base64String: string): Uint8Array<ArrayBuffer> {\n const padding = \"=\".repeat((4 - (base64String.length % 4)) % 4);\n const base64 = (base64String + padding).replace(/-/g, \"+\").replace(/_/g, \"/\");\n const rawData = atob(base64);\n const buffer = new ArrayBuffer(rawData.length);\n const output = new Uint8Array(buffer);\n for (let i = 0; i < rawData.length; i++) {\n output[i] = rawData.charCodeAt(i);\n }\n return output;\n}\n\n/**\n * Convenience check for environments where the Push API is unavailable\n * (Safari iOS without PWA install, older browsers, SSR, etc.).\n */\nexport function isPushSupported(): boolean {\n return (\n typeof window !== \"undefined\" &&\n \"serviceWorker\" in navigator &&\n \"PushManager\" in window &&\n \"Notification\" in window\n );\n}\n"],"mappings":";AAYA,SAAgB,EAAsB,GAA+C;CAEjF,IAAM,KAAU,IADA,IAAI,QAAQ,IAAK,EAAa,SAAS,KAAM,CAC9B,EAAA,CAAS,QAAQ,MAAM,GAAG,CAAC,CAAC,QAAQ,MAAM,GAAG,GACtE,IAAU,KAAK,CAAM,GACrB,IAAS,IAAI,YAAY,EAAQ,MAAM,GACvC,IAAS,IAAI,WAAW,CAAM;CACpC,KAAK,IAAI,IAAI,GAAG,IAAI,EAAQ,QAAQ,KAChC,EAAO,KAAK,EAAQ,WAAW,CAAC;CAEpC,OAAO;AACX;AAMA,SAAgB,IAA2B;CACvC,OACI,OAAO,SAAW,OAClB,mBAAmB,aACnB,iBAAiB,UACjB,kBAAkB;AAE1B"}
|