@hanzo/ui 8.27.8 → 8.27.9
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 +2 -1
- package/dist/canvas.cjs +3 -3
- package/dist/canvas.js +3 -3
- package/dist/canvas.js.map +1 -1
- package/dist/gallery.html +2 -2
- package/dist/grid.cjs +19 -43
- package/dist/grid.d.ts +36 -1
- package/dist/grid.d.ts.map +1 -1
- package/dist/grid.js +19 -43
- package/dist/grid.js.map +1 -1
- package/dist/product/ChunkGuard.cjs +58 -0
- package/dist/product/ChunkGuard.d.ts +7 -0
- package/dist/product/ChunkGuard.d.ts.map +1 -0
- package/dist/product/ChunkGuard.js +56 -0
- package/dist/product/ChunkGuard.js.map +1 -0
- package/dist/product/DetailPane.cjs +46 -0
- package/dist/product/DetailPane.d.ts +47 -0
- package/dist/product/DetailPane.d.ts.map +1 -0
- package/dist/product/DetailPane.js +43 -0
- package/dist/product/DetailPane.js.map +1 -0
- package/dist/product/Fact.cjs +19 -0
- package/dist/product/Fact.d.ts +23 -0
- package/dist/product/Fact.d.ts.map +1 -0
- package/dist/product/Fact.js +17 -0
- package/dist/product/Fact.js.map +1 -0
- package/dist/product/chunkGuard.logic.cjs +54 -0
- package/dist/product/chunkGuard.logic.d.ts +26 -0
- package/dist/product/chunkGuard.logic.d.ts.map +1 -0
- package/dist/product/chunkGuard.logic.js +49 -0
- package/dist/product/chunkGuard.logic.js.map +1 -0
- package/dist/product/index.cjs +10 -0
- package/dist/product/index.d.ts +3 -0
- package/dist/product/index.d.ts.map +1 -1
- package/dist/product/index.js +10 -0
- package/dist/product/index.js.map +1 -1
- package/package.json +5 -3
package/dist/grid.cjs
CHANGED
|
@@ -3,51 +3,27 @@
|
|
|
3
3
|
Object.defineProperty(exports, "__esModule", { value: true });
|
|
4
4
|
exports.Cell = exports.Grid = exports.tracks = void 0;
|
|
5
5
|
const jsx_runtime_1 = require("react/jsx-runtime");
|
|
6
|
+
/** `'$3'` -> 12. A raw number passes through as px. */
|
|
6
7
|
/**
|
|
7
|
-
*
|
|
8
|
-
*
|
|
9
|
-
* This exists to kill a specific shipped defect: hand-rolled
|
|
10
|
-
* `width="calc(25% - 7.5px)"` grids that collapse asymmetrically. That shape is
|
|
11
|
-
* broken by construction — each child computes its own width, so the row is only
|
|
12
|
-
* even while every child agrees, and one long word or one `box-sizing` surprise
|
|
13
|
-
* makes the row ragged. Nothing about it can be fixed by tuning the number.
|
|
14
|
-
*
|
|
15
|
-
* Here the parent declares the tracks once and the children have no say. Equal
|
|
16
|
-
* columns are structural, not arithmetic, and no child can widen its own track.
|
|
17
|
-
*
|
|
18
|
-
* WEB ONLY, which is why it sits at `@hanzo/ui/grid` rather than on the barrel,
|
|
19
|
-
* beside `@hanzo/ui/dots`. That is a statement about this file and nothing else:
|
|
20
|
-
* it renders a `div` and sets `display: grid`, and neither of those exists on
|
|
21
|
-
* React Native — Yoga has grid data structures but no grid algorithm, so
|
|
22
|
-
* `display: 'grid'` is not in the platform's style types at all.
|
|
8
|
+
* A gap, as a CSS length.
|
|
23
9
|
*
|
|
24
|
-
*
|
|
25
|
-
*
|
|
26
|
-
*
|
|
27
|
-
*
|
|
10
|
+
* This asked `getTokenValue` for a number and fell back to 12 when it did not
|
|
11
|
+
* get one. It never got one: measured across a consuming app, every `$n` gap
|
|
12
|
+
* rendered at 12px — `gap="$4"` drew 12 where `--space-4` is 16, and thirty of
|
|
13
|
+
* thirty-four call sites were silently wrong. The four that looked right were
|
|
14
|
+
* the ones passing a bare number.
|
|
28
15
|
*
|
|
29
|
-
*
|
|
30
|
-
*
|
|
31
|
-
*
|
|
32
|
-
*
|
|
33
|
-
*
|
|
34
|
-
*
|
|
35
|
-
* The min-width floor every grid child needs is declared ONCE, as
|
|
36
|
-
* `[data-slot='grid'] > *` in `styles/motion.css`. It is not restated inline
|
|
37
|
-
* here: a grid item's `grid-column` only applies to a direct child of the grid,
|
|
38
|
-
* so a `Cell` is always in range of that selector, and a second copy inline
|
|
39
|
-
* would be a second place for the same invariant to be edited.
|
|
16
|
+
* The ladder those tokens name is already in the document as custom properties
|
|
17
|
+
* and already correct, so this reads it there. That fixes the number and gains
|
|
18
|
+
* the property the JS lookup could not have: `var(--space-4)` follows the
|
|
19
|
+
* ladder while the page is open, so a person moving density in an appearance
|
|
20
|
+
* panel moves every grid with it. A number resolved at render is fixed at
|
|
21
|
+
* render.
|
|
40
22
|
*/
|
|
41
|
-
const
|
|
42
|
-
|
|
43
|
-
|
|
44
|
-
|
|
45
|
-
return fallback;
|
|
46
|
-
if (typeof v === 'number')
|
|
47
|
-
return v;
|
|
48
|
-
const t = (0, gui_1.getTokenValue)(v, 'space');
|
|
49
|
-
return typeof t === 'number' ? t : fallback;
|
|
50
|
-
};
|
|
23
|
+
const space = (v, fallback) => v == null ? `${fallback}px`
|
|
24
|
+
: typeof v === 'number' ? `${v}px`
|
|
25
|
+
: v.startsWith('$') ? `var(--space-${v.slice(1)}, ${fallback}px)`
|
|
26
|
+
: v;
|
|
51
27
|
const fit = (v) => typeof v === 'object' && v !== null && !Array.isArray(v);
|
|
52
28
|
/** One track. A bare number is px; anything else is already a track size. */
|
|
53
29
|
const track = (v) => (typeof v === 'number' ? `${v}px` : v);
|
|
@@ -79,7 +55,7 @@ const list = (t) => {
|
|
|
79
55
|
*/
|
|
80
56
|
const fitted = ({ min, max }, gap) => {
|
|
81
57
|
const floor = max
|
|
82
|
-
? `max(min(${min}px, 100%), calc((100% - ${
|
|
58
|
+
? `max(min(${min}px, 100%), calc((100% - ${max - 1} * ${gap}) / ${max}))`
|
|
83
59
|
: `min(${min}px, 100%)`;
|
|
84
60
|
return `repeat(auto-fill, minmax(${floor}, 1fr))`;
|
|
85
61
|
};
|
|
@@ -90,7 +66,7 @@ const fitted = ({ min, max }, gap) => {
|
|
|
90
66
|
* the whole reason this component exists and are each one edit away from being
|
|
91
67
|
* tidied back into the ragged row.
|
|
92
68
|
*/
|
|
93
|
-
const tracks = (columns, gap =
|
|
69
|
+
const tracks = (columns, gap = '0px') => fit(columns) ? fitted(columns, gap) : list(columns);
|
|
94
70
|
exports.tracks = tracks;
|
|
95
71
|
const Grid = ({ columns = { min: 240 }, rows, gap = '$3', style, ...props }) => {
|
|
96
72
|
const g = space(gap, 12);
|
package/dist/grid.d.ts
CHANGED
|
@@ -1,3 +1,38 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* Grid — a real CSS grid whose tracks come from the CONTAINER, not the children.
|
|
3
|
+
*
|
|
4
|
+
* This exists to kill a specific shipped defect: hand-rolled
|
|
5
|
+
* `width="calc(25% - 7.5px)"` grids that collapse asymmetrically. That shape is
|
|
6
|
+
* broken by construction — each child computes its own width, so the row is only
|
|
7
|
+
* even while every child agrees, and one long word or one `box-sizing` surprise
|
|
8
|
+
* makes the row ragged. Nothing about it can be fixed by tuning the number.
|
|
9
|
+
*
|
|
10
|
+
* Here the parent declares the tracks once and the children have no say. Equal
|
|
11
|
+
* columns are structural, not arithmetic, and no child can widen its own track.
|
|
12
|
+
*
|
|
13
|
+
* WEB ONLY, which is why it sits at `@hanzo/ui/grid` rather than on the barrel,
|
|
14
|
+
* beside `@hanzo/ui/dots`. That is a statement about this file and nothing else:
|
|
15
|
+
* it renders a `div` and sets `display: grid`, and neither of those exists on
|
|
16
|
+
* React Native — Yoga has grid data structures but no grid algorithm, so
|
|
17
|
+
* `display: 'grid'` is not in the platform's style types at all.
|
|
18
|
+
*
|
|
19
|
+
* The quarantine is a pin, not a law, and the API is named so that lifting it
|
|
20
|
+
* costs nothing: `columns` and `rows` are TRACK LISTS and `Cell` places and
|
|
21
|
+
* spans, all of them CSS-grid concepts rather than facts about the div. When a
|
|
22
|
+
* native grid engine lands, this file changes and call sites do not.
|
|
23
|
+
*
|
|
24
|
+
* Why a plain div and not a gui YStack: gui's box model is Yoga, which is
|
|
25
|
+
* flexbox here — a YStack would compile its own `display:flex` atomic class and
|
|
26
|
+
* fight the grid. Inline styles, not a stylesheet class, so there is no rule to
|
|
27
|
+
* fail to ship: this package's own checker exists because "class with no rule"
|
|
28
|
+
* has shipped here three times.
|
|
29
|
+
*
|
|
30
|
+
* The min-width floor every grid child needs is declared ONCE, as
|
|
31
|
+
* `[data-slot='grid'] > *` in `styles/motion.css`. It is not restated inline
|
|
32
|
+
* here: a grid item's `grid-column` only applies to a direct child of the grid,
|
|
33
|
+
* so a `Cell` is always in range of that selector, and a second copy inline
|
|
34
|
+
* would be a second place for the same invariant to be edited.
|
|
35
|
+
*/
|
|
1
36
|
import type { ComponentProps, ReactNode } from 'react';
|
|
2
37
|
/**
|
|
3
38
|
* A track list, in the spellings a caller actually has. Every one of these is
|
|
@@ -44,7 +79,7 @@ export interface GridProps extends Omit<ComponentProps<'div'>, 'children'> {
|
|
|
44
79
|
* the whole reason this component exists and are each one edit away from being
|
|
45
80
|
* tidied back into the ragged row.
|
|
46
81
|
*/
|
|
47
|
-
export declare const tracks: (columns: Tracks | Fit, gap?:
|
|
82
|
+
export declare const tracks: (columns: Tracks | Fit, gap?: string) => string;
|
|
48
83
|
declare const Grid: ({ columns, rows, gap, style, ...props }: GridProps) => import("react").JSX.Element;
|
|
49
84
|
export interface CellProps extends ComponentProps<'div'> {
|
|
50
85
|
/**
|
package/dist/grid.d.ts.map
CHANGED
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"grid.d.ts","sourceRoot":"","sources":["../src/grid.tsx"],"names":[],"mappings":"
|
|
1
|
+
{"version":3,"file":"grid.d.ts","sourceRoot":"","sources":["../src/grid.tsx"],"names":[],"mappings":"AAEA;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;GAkCG;AACH,OAAO,KAAK,EAAE,cAAc,EAAiB,SAAS,EAAE,MAAM,OAAO,CAAA;AAErE;;;;;;;GAOG;AACH,MAAM,MAAM,MAAM,GAAG,MAAM,GAAG,MAAM,GAAG,KAAK,CAAC,MAAM,GAAG,MAAM,CAAC,CAAA;AAE7D;;;;;;GAMG;AACH,MAAM,WAAW,GAAG;IAClB,4DAA4D;IAC5D,GAAG,EAAE,MAAM,CAAA;IACX;;;;;;;OAOG;IACH,GAAG,CAAC,EAAE,MAAM,CAAA;CACb;AAED,MAAM,WAAW,SAAU,SAAQ,IAAI,CAAC,cAAc,CAAC,KAAK,CAAC,EAAE,UAAU,CAAC;IACxE,wEAAwE;IACxE,OAAO,CAAC,EAAE,MAAM,GAAG,GAAG,CAAA;IACtB,qEAAqE;IACrE,IAAI,CAAC,EAAE,MAAM,CAAA;IACb,6CAA6C;IAC7C,GAAG,CAAC,EAAE,MAAM,GAAG,MAAM,CAAA;IACrB,QAAQ,CAAC,EAAE,SAAS,CAAA;CACrB;AA8DD;;;;;;GAMG;AACH,eAAO,MAAM,MAAM,YAAa,MAAM,GAAG,GAAG,mBAAgB,MACP,CAAA;AAErD,QAAA,MAAM,IAAI,4CAAmE,SAAS,gCASrF,CAAA;AAED,MAAM,WAAW,SAAU,SAAQ,cAAc,CAAC,KAAK,CAAC;IACtD;;;;OAIG;IACH,GAAG,CAAC,EAAE,MAAM,GAAG,MAAM,CAAA;IACrB,8CAA8C;IAC9C,GAAG,CAAC,EAAE,MAAM,GAAG,MAAM,CAAA;CACtB;AAMD,QAAA,MAAM,IAAI,kCAAmC,SAAS,gCAMrD,CAAA;AAED,OAAO,EAAE,IAAI,EAAE,IAAI,EAAE,CAAA"}
|
package/dist/grid.js
CHANGED
|
@@ -1,50 +1,26 @@
|
|
|
1
1
|
'use client';
|
|
2
2
|
import { jsx as _jsx } from "react/jsx-runtime";
|
|
3
|
+
/** `'$3'` -> 12. A raw number passes through as px. */
|
|
3
4
|
/**
|
|
4
|
-
*
|
|
5
|
-
*
|
|
6
|
-
* This exists to kill a specific shipped defect: hand-rolled
|
|
7
|
-
* `width="calc(25% - 7.5px)"` grids that collapse asymmetrically. That shape is
|
|
8
|
-
* broken by construction — each child computes its own width, so the row is only
|
|
9
|
-
* even while every child agrees, and one long word or one `box-sizing` surprise
|
|
10
|
-
* makes the row ragged. Nothing about it can be fixed by tuning the number.
|
|
11
|
-
*
|
|
12
|
-
* Here the parent declares the tracks once and the children have no say. Equal
|
|
13
|
-
* columns are structural, not arithmetic, and no child can widen its own track.
|
|
14
|
-
*
|
|
15
|
-
* WEB ONLY, which is why it sits at `@hanzo/ui/grid` rather than on the barrel,
|
|
16
|
-
* beside `@hanzo/ui/dots`. That is a statement about this file and nothing else:
|
|
17
|
-
* it renders a `div` and sets `display: grid`, and neither of those exists on
|
|
18
|
-
* React Native — Yoga has grid data structures but no grid algorithm, so
|
|
19
|
-
* `display: 'grid'` is not in the platform's style types at all.
|
|
5
|
+
* A gap, as a CSS length.
|
|
20
6
|
*
|
|
21
|
-
*
|
|
22
|
-
*
|
|
23
|
-
*
|
|
24
|
-
*
|
|
7
|
+
* This asked `getTokenValue` for a number and fell back to 12 when it did not
|
|
8
|
+
* get one. It never got one: measured across a consuming app, every `$n` gap
|
|
9
|
+
* rendered at 12px — `gap="$4"` drew 12 where `--space-4` is 16, and thirty of
|
|
10
|
+
* thirty-four call sites were silently wrong. The four that looked right were
|
|
11
|
+
* the ones passing a bare number.
|
|
25
12
|
*
|
|
26
|
-
*
|
|
27
|
-
*
|
|
28
|
-
*
|
|
29
|
-
*
|
|
30
|
-
*
|
|
31
|
-
*
|
|
32
|
-
* The min-width floor every grid child needs is declared ONCE, as
|
|
33
|
-
* `[data-slot='grid'] > *` in `styles/motion.css`. It is not restated inline
|
|
34
|
-
* here: a grid item's `grid-column` only applies to a direct child of the grid,
|
|
35
|
-
* so a `Cell` is always in range of that selector, and a second copy inline
|
|
36
|
-
* would be a second place for the same invariant to be edited.
|
|
13
|
+
* The ladder those tokens name is already in the document as custom properties
|
|
14
|
+
* and already correct, so this reads it there. That fixes the number and gains
|
|
15
|
+
* the property the JS lookup could not have: `var(--space-4)` follows the
|
|
16
|
+
* ladder while the page is open, so a person moving density in an appearance
|
|
17
|
+
* panel moves every grid with it. A number resolved at render is fixed at
|
|
18
|
+
* render.
|
|
37
19
|
*/
|
|
38
|
-
|
|
39
|
-
|
|
40
|
-
|
|
41
|
-
|
|
42
|
-
return fallback;
|
|
43
|
-
if (typeof v === 'number')
|
|
44
|
-
return v;
|
|
45
|
-
const t = getTokenValue(v, 'space');
|
|
46
|
-
return typeof t === 'number' ? t : fallback;
|
|
47
|
-
};
|
|
20
|
+
const space = (v, fallback) => v == null ? `${fallback}px`
|
|
21
|
+
: typeof v === 'number' ? `${v}px`
|
|
22
|
+
: v.startsWith('$') ? `var(--space-${v.slice(1)}, ${fallback}px)`
|
|
23
|
+
: v;
|
|
48
24
|
const fit = (v) => typeof v === 'object' && v !== null && !Array.isArray(v);
|
|
49
25
|
/** One track. A bare number is px; anything else is already a track size. */
|
|
50
26
|
const track = (v) => (typeof v === 'number' ? `${v}px` : v);
|
|
@@ -76,7 +52,7 @@ const list = (t) => {
|
|
|
76
52
|
*/
|
|
77
53
|
const fitted = ({ min, max }, gap) => {
|
|
78
54
|
const floor = max
|
|
79
|
-
? `max(min(${min}px, 100%), calc((100% - ${
|
|
55
|
+
? `max(min(${min}px, 100%), calc((100% - ${max - 1} * ${gap}) / ${max}))`
|
|
80
56
|
: `min(${min}px, 100%)`;
|
|
81
57
|
return `repeat(auto-fill, minmax(${floor}, 1fr))`;
|
|
82
58
|
};
|
|
@@ -87,7 +63,7 @@ const fitted = ({ min, max }, gap) => {
|
|
|
87
63
|
* the whole reason this component exists and are each one edit away from being
|
|
88
64
|
* tidied back into the ragged row.
|
|
89
65
|
*/
|
|
90
|
-
export const tracks = (columns, gap =
|
|
66
|
+
export const tracks = (columns, gap = '0px') => fit(columns) ? fitted(columns, gap) : list(columns);
|
|
91
67
|
const Grid = ({ columns = { min: 240 }, rows, gap = '$3', style, ...props }) => {
|
|
92
68
|
const g = space(gap, 12);
|
|
93
69
|
const grid = {
|
package/dist/grid.js.map
CHANGED
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"grid.js","sourceRoot":"","sources":["../src/grid.tsx"],"names":[],"mappings":"AAAA,YAAY,CAAA;;
|
|
1
|
+
{"version":3,"file":"grid.js","sourceRoot":"","sources":["../src/grid.tsx"],"names":[],"mappings":"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"}
|
|
@@ -0,0 +1,58 @@
|
|
|
1
|
+
'use client';"use strict";
|
|
2
|
+
'use client';
|
|
3
|
+
Object.defineProperty(exports, "__esModule", { value: true });
|
|
4
|
+
exports.ChunkGuard = ChunkGuard;
|
|
5
|
+
/**
|
|
6
|
+
* ChunkGuard — window-level net that recovers from a stale-deploy chunk 404.
|
|
7
|
+
* Renders nothing; mount it once near the shell root.
|
|
8
|
+
*
|
|
9
|
+
* Two catch surfaces, because a chunk 404 surfaces two ways:
|
|
10
|
+
* - CAPTURE-phase `error` on the failing `<script>`/`<link>` element — a
|
|
11
|
+
* resource load error does NOT bubble, so only a capture listener sees
|
|
12
|
+
* it. This fires on the RAW 404 during the initial deep-link load,
|
|
13
|
+
* before the loader even rejects — the earliest, most reliable signal.
|
|
14
|
+
* - `unhandledrejection` / bubbled `error` carrying a `ChunkLoadError` —
|
|
15
|
+
* the dynamic-import path.
|
|
16
|
+
*
|
|
17
|
+
* A render-time error boundary catches the same class at RENDER time; this
|
|
18
|
+
* complements it for the async/resource paths a boundary never sees. See
|
|
19
|
+
* `chunkGuard.logic.ts` for the pure decisions this wires up.
|
|
20
|
+
*/
|
|
21
|
+
const react_1 = require("react");
|
|
22
|
+
const chunkGuard_logic_1 = require("./chunkGuard.logic.cjs");
|
|
23
|
+
function ChunkGuard({ assetPathPrefix } = {}) {
|
|
24
|
+
(0, react_1.useEffect)(() => {
|
|
25
|
+
// Reload at most once per window, so a skew that trips several
|
|
26
|
+
// detectors at once reloads ONCE — never a reload loop.
|
|
27
|
+
const recover = () => {
|
|
28
|
+
try {
|
|
29
|
+
const raw = window.sessionStorage.getItem(chunkGuard_logic_1.CHUNK_RELOAD_AT_KEY);
|
|
30
|
+
const last = raw ? Number(raw) : null;
|
|
31
|
+
if (!(0, chunkGuard_logic_1.shouldReloadForChunk)(Date.now(), last))
|
|
32
|
+
return;
|
|
33
|
+
window.sessionStorage.setItem(chunkGuard_logic_1.CHUNK_RELOAD_AT_KEY, String(Date.now()));
|
|
34
|
+
window.location.reload();
|
|
35
|
+
}
|
|
36
|
+
catch {
|
|
37
|
+
/* sessionStorage blocked (private mode) — let a render boundary show its card */
|
|
38
|
+
}
|
|
39
|
+
};
|
|
40
|
+
const onError = (e) => {
|
|
41
|
+
if ((0, chunkGuard_logic_1.isBuildAssetError)(e.target, assetPathPrefix) || (0, chunkGuard_logic_1.isChunkLoadError)(e.error ?? e.message))
|
|
42
|
+
recover();
|
|
43
|
+
};
|
|
44
|
+
const onRejection = (e) => {
|
|
45
|
+
if ((0, chunkGuard_logic_1.isChunkLoadError)(e.reason))
|
|
46
|
+
recover();
|
|
47
|
+
};
|
|
48
|
+
// `capture: true` so the non-bubbling resource-load error on a 404'd
|
|
49
|
+
// chunk element reaches us.
|
|
50
|
+
window.addEventListener('error', onError, true);
|
|
51
|
+
window.addEventListener('unhandledrejection', onRejection);
|
|
52
|
+
return () => {
|
|
53
|
+
window.removeEventListener('error', onError, true);
|
|
54
|
+
window.removeEventListener('unhandledrejection', onRejection);
|
|
55
|
+
};
|
|
56
|
+
}, [assetPathPrefix]);
|
|
57
|
+
return null;
|
|
58
|
+
}
|
|
@@ -0,0 +1,7 @@
|
|
|
1
|
+
export type ChunkGuardProps = {
|
|
2
|
+
/** Path fragment identifying a build asset URL. Default `/_next/static/`
|
|
3
|
+
* (Next.js); pass the bundler's own prefix on another host. */
|
|
4
|
+
assetPathPrefix?: string;
|
|
5
|
+
};
|
|
6
|
+
export declare function ChunkGuard({ assetPathPrefix }?: ChunkGuardProps): null;
|
|
7
|
+
//# sourceMappingURL=ChunkGuard.d.ts.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"ChunkGuard.d.ts","sourceRoot":"","sources":["../../src/product/ChunkGuard.tsx"],"names":[],"mappings":"AAsBA,MAAM,MAAM,eAAe,GAAG;IAC5B;oEACgE;IAChE,eAAe,CAAC,EAAE,MAAM,CAAA;CACzB,CAAA;AAED,wBAAgB,UAAU,CAAC,EAAE,eAAe,EAAE,GAAE,eAAoB,QAkCnE"}
|
|
@@ -0,0 +1,56 @@
|
|
|
1
|
+
'use client';
|
|
2
|
+
/**
|
|
3
|
+
* ChunkGuard — window-level net that recovers from a stale-deploy chunk 404.
|
|
4
|
+
* Renders nothing; mount it once near the shell root.
|
|
5
|
+
*
|
|
6
|
+
* Two catch surfaces, because a chunk 404 surfaces two ways:
|
|
7
|
+
* - CAPTURE-phase `error` on the failing `<script>`/`<link>` element — a
|
|
8
|
+
* resource load error does NOT bubble, so only a capture listener sees
|
|
9
|
+
* it. This fires on the RAW 404 during the initial deep-link load,
|
|
10
|
+
* before the loader even rejects — the earliest, most reliable signal.
|
|
11
|
+
* - `unhandledrejection` / bubbled `error` carrying a `ChunkLoadError` —
|
|
12
|
+
* the dynamic-import path.
|
|
13
|
+
*
|
|
14
|
+
* A render-time error boundary catches the same class at RENDER time; this
|
|
15
|
+
* complements it for the async/resource paths a boundary never sees. See
|
|
16
|
+
* `chunkGuard.logic.ts` for the pure decisions this wires up.
|
|
17
|
+
*/
|
|
18
|
+
import { useEffect } from 'react';
|
|
19
|
+
import { isBuildAssetError, isChunkLoadError, shouldReloadForChunk, CHUNK_RELOAD_AT_KEY } from './chunkGuard.logic.js';
|
|
20
|
+
export function ChunkGuard({ assetPathPrefix } = {}) {
|
|
21
|
+
useEffect(() => {
|
|
22
|
+
// Reload at most once per window, so a skew that trips several
|
|
23
|
+
// detectors at once reloads ONCE — never a reload loop.
|
|
24
|
+
const recover = () => {
|
|
25
|
+
try {
|
|
26
|
+
const raw = window.sessionStorage.getItem(CHUNK_RELOAD_AT_KEY);
|
|
27
|
+
const last = raw ? Number(raw) : null;
|
|
28
|
+
if (!shouldReloadForChunk(Date.now(), last))
|
|
29
|
+
return;
|
|
30
|
+
window.sessionStorage.setItem(CHUNK_RELOAD_AT_KEY, String(Date.now()));
|
|
31
|
+
window.location.reload();
|
|
32
|
+
}
|
|
33
|
+
catch {
|
|
34
|
+
/* sessionStorage blocked (private mode) — let a render boundary show its card */
|
|
35
|
+
}
|
|
36
|
+
};
|
|
37
|
+
const onError = (e) => {
|
|
38
|
+
if (isBuildAssetError(e.target, assetPathPrefix) || isChunkLoadError(e.error ?? e.message))
|
|
39
|
+
recover();
|
|
40
|
+
};
|
|
41
|
+
const onRejection = (e) => {
|
|
42
|
+
if (isChunkLoadError(e.reason))
|
|
43
|
+
recover();
|
|
44
|
+
};
|
|
45
|
+
// `capture: true` so the non-bubbling resource-load error on a 404'd
|
|
46
|
+
// chunk element reaches us.
|
|
47
|
+
window.addEventListener('error', onError, true);
|
|
48
|
+
window.addEventListener('unhandledrejection', onRejection);
|
|
49
|
+
return () => {
|
|
50
|
+
window.removeEventListener('error', onError, true);
|
|
51
|
+
window.removeEventListener('unhandledrejection', onRejection);
|
|
52
|
+
};
|
|
53
|
+
}, [assetPathPrefix]);
|
|
54
|
+
return null;
|
|
55
|
+
}
|
|
56
|
+
//# sourceMappingURL=ChunkGuard.js.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"ChunkGuard.js","sourceRoot":"","sources":["../../src/product/ChunkGuard.tsx"],"names":[],"mappings":"AAAA,YAAY,CAAA;AAEZ;;;;;;;;;;;;;;;GAeG;AACH,OAAO,EAAE,SAAS,EAAE,MAAM,OAAO,CAAA;AAEjC,OAAO,EAAE,iBAAiB,EAAE,gBAAgB,EAAE,oBAAoB,EAAE,mBAAmB,EAAE,MAAM,oBAAoB,CAAA;AAQnH,MAAM,UAAU,UAAU,CAAC,EAAE,eAAe,EAAE,GAAoB,EAAE;IAClE,SAAS,CAAC,GAAG,EAAE;QACb,+DAA+D;QAC/D,wDAAwD;QACxD,MAAM,OAAO,GAAG,GAAG,EAAE;YACnB,IAAI,CAAC;gBACH,MAAM,GAAG,GAAG,MAAM,CAAC,cAAc,CAAC,OAAO,CAAC,mBAAmB,CAAC,CAAA;gBAC9D,MAAM,IAAI,GAAG,GAAG,CAAC,CAAC,CAAC,MAAM,CAAC,GAAG,CAAC,CAAC,CAAC,CAAC,IAAI,CAAA;gBACrC,IAAI,CAAC,oBAAoB,CAAC,IAAI,CAAC,GAAG,EAAE,EAAE,IAAI,CAAC;oBAAE,OAAM;gBACnD,MAAM,CAAC,cAAc,CAAC,OAAO,CAAC,mBAAmB,EAAE,MAAM,CAAC,IAAI,CAAC,GAAG,EAAE,CAAC,CAAC,CAAA;gBACtE,MAAM,CAAC,QAAQ,CAAC,MAAM,EAAE,CAAA;YAC1B,CAAC;YAAC,MAAM,CAAC;gBACP,iFAAiF;YACnF,CAAC;QACH,CAAC,CAAA;QAED,MAAM,OAAO,GAAG,CAAC,CAAa,EAAE,EAAE;YAChC,IAAI,iBAAiB,CAAC,CAAC,CAAC,MAAM,EAAE,eAAe,CAAC,IAAI,gBAAgB,CAAC,CAAC,CAAC,KAAK,IAAI,CAAC,CAAC,OAAO,CAAC;gBAAE,OAAO,EAAE,CAAA;QACvG,CAAC,CAAA;QACD,MAAM,WAAW,GAAG,CAAC,CAAwB,EAAE,EAAE;YAC/C,IAAI,gBAAgB,CAAC,CAAC,CAAC,MAAM,CAAC;gBAAE,OAAO,EAAE,CAAA;QAC3C,CAAC,CAAA;QAED,qEAAqE;QACrE,4BAA4B;QAC5B,MAAM,CAAC,gBAAgB,CAAC,OAAO,EAAE,OAAO,EAAE,IAAI,CAAC,CAAA;QAC/C,MAAM,CAAC,gBAAgB,CAAC,oBAAoB,EAAE,WAAW,CAAC,CAAA;QAC1D,OAAO,GAAG,EAAE;YACV,MAAM,CAAC,mBAAmB,CAAC,OAAO,EAAE,OAAO,EAAE,IAAI,CAAC,CAAA;YAClD,MAAM,CAAC,mBAAmB,CAAC,oBAAoB,EAAE,WAAW,CAAC,CAAA;QAC/D,CAAC,CAAA;IACH,CAAC,EAAE,CAAC,eAAe,CAAC,CAAC,CAAA;IAErB,OAAO,IAAI,CAAA;AACb,CAAC"}
|
|
@@ -0,0 +1,46 @@
|
|
|
1
|
+
'use client';"use strict";
|
|
2
|
+
'use client';
|
|
3
|
+
Object.defineProperty(exports, "__esModule", { value: true });
|
|
4
|
+
exports.useDetailPane = useDetailPane;
|
|
5
|
+
exports.DetailPane = DetailPane;
|
|
6
|
+
const jsx_runtime_1 = require("react/jsx-runtime");
|
|
7
|
+
/**
|
|
8
|
+
* DetailPane — the ONE reusable right-side pane for viewing or editing the
|
|
9
|
+
* details of an item. A product does NOT build its own pane: it writes a
|
|
10
|
+
* DESCRIPTOR (`{ title, subtitle?, icon?, content, footer? }`) and calls
|
|
11
|
+
* `useDetailPane().open(descriptor)`. The pane slides out from the right
|
|
12
|
+
* (full-screen on mobile) via `SlideOver`, so every "open item detail" looks
|
|
13
|
+
* and behaves identically (DRY).
|
|
14
|
+
*
|
|
15
|
+
* Rendered ONCE near the shell root; any module — a row, a list item, a
|
|
16
|
+
* pinned form — opens the same pane. Interactive content closes itself with
|
|
17
|
+
* `useDetailPane().close()`.
|
|
18
|
+
*
|
|
19
|
+
* The last descriptor stays mounted through the close transition, so the exit
|
|
20
|
+
* animates with its content (no flash of empty pane). Opening a new
|
|
21
|
+
* descriptor replaces it.
|
|
22
|
+
*/
|
|
23
|
+
const react_1 = require("react");
|
|
24
|
+
const gui_1 = require("@hanzo/gui");
|
|
25
|
+
const lucide_icons_2_1 = require("@hanzogui/lucide-icons-2");
|
|
26
|
+
const SlideOver_1 = require("./SlideOver.cjs");
|
|
27
|
+
const color_1 = require("./color.cjs");
|
|
28
|
+
const Ctx = (0, react_1.createContext)(null);
|
|
29
|
+
function useDetailPane() {
|
|
30
|
+
const ctx = (0, react_1.useContext)(Ctx);
|
|
31
|
+
if (!ctx)
|
|
32
|
+
throw new Error('useDetailPane must be used within <DetailPane>');
|
|
33
|
+
return ctx;
|
|
34
|
+
}
|
|
35
|
+
function DetailPane({ children, zIndex }) {
|
|
36
|
+
const [isOpen, setIsOpen] = (0, react_1.useState)(false);
|
|
37
|
+
const [desc, setDesc] = (0, react_1.useState)(null);
|
|
38
|
+
const open = (0, react_1.useCallback)((descriptor) => {
|
|
39
|
+
setDesc(descriptor);
|
|
40
|
+
setIsOpen(true);
|
|
41
|
+
}, []);
|
|
42
|
+
const close = (0, react_1.useCallback)(() => setIsOpen(false), []);
|
|
43
|
+
const api = (0, react_1.useMemo)(() => ({ open, close, isOpen }), [open, close, isOpen]);
|
|
44
|
+
const Icon = desc?.icon;
|
|
45
|
+
return ((0, jsx_runtime_1.jsxs)(Ctx.Provider, { value: api, children: [children, (0, jsx_runtime_1.jsxs)(SlideOver_1.SlideOver, { open: isOpen, onClose: close, side: "right", size: desc?.size ?? 460, ariaLabel: typeof desc?.title === 'string' ? desc?.title : 'Details', zIndex: zIndex, children: [(0, jsx_runtime_1.jsxs)(gui_1.XStack, { items: "center", gap: "$2.5", px: "$4", height: 56, borderBottomWidth: 1, borderColor: "$borderColor", children: [Icon ? (0, jsx_runtime_1.jsx)(Icon, { size: 18, color: desc?.iconColor ? (0, color_1.asColor)(desc.iconColor) : undefined }) : null, (0, jsx_runtime_1.jsxs)(gui_1.YStack, { flex: 1, minW: 0, children: [(0, jsx_runtime_1.jsx)(gui_1.Text, { fontSize: "$5", fontWeight: "700", color: "$color12", numberOfLines: 1, children: desc?.title }), desc?.subtitle !== undefined ? ((0, jsx_runtime_1.jsx)(gui_1.Text, { fontSize: "$2", color: "$color10", numberOfLines: 1, children: desc?.subtitle })) : null] }), (0, jsx_runtime_1.jsx)(gui_1.Button, { size: "$2", chromeless: true, icon: (0, jsx_runtime_1.jsx)(lucide_icons_2_1.X, { size: 18 }), onPress: close, "aria-label": "Close" })] }), (0, jsx_runtime_1.jsx)(gui_1.ScrollView, { flex: 1, minH: 0, children: (0, jsx_runtime_1.jsx)(gui_1.YStack, { p: "$4", gap: "$3", children: desc?.content }) }), desc?.footer !== undefined ? ((0, jsx_runtime_1.jsx)(gui_1.XStack, { px: "$4", py: "$3", gap: "$2", borderTopWidth: 1, borderColor: "$borderColor", bg: "$color1", children: desc?.footer })) : null] })] }));
|
|
46
|
+
}
|
|
@@ -0,0 +1,47 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* DetailPane — the ONE reusable right-side pane for viewing or editing the
|
|
3
|
+
* details of an item. A product does NOT build its own pane: it writes a
|
|
4
|
+
* DESCRIPTOR (`{ title, subtitle?, icon?, content, footer? }`) and calls
|
|
5
|
+
* `useDetailPane().open(descriptor)`. The pane slides out from the right
|
|
6
|
+
* (full-screen on mobile) via `SlideOver`, so every "open item detail" looks
|
|
7
|
+
* and behaves identically (DRY).
|
|
8
|
+
*
|
|
9
|
+
* Rendered ONCE near the shell root; any module — a row, a list item, a
|
|
10
|
+
* pinned form — opens the same pane. Interactive content closes itself with
|
|
11
|
+
* `useDetailPane().close()`.
|
|
12
|
+
*
|
|
13
|
+
* The last descriptor stays mounted through the close transition, so the exit
|
|
14
|
+
* animates with its content (no flash of empty pane). Opening a new
|
|
15
|
+
* descriptor replaces it.
|
|
16
|
+
*/
|
|
17
|
+
import { type ReactNode } from 'react';
|
|
18
|
+
import { type IconLike } from './color.js';
|
|
19
|
+
export type DetailDescriptor = {
|
|
20
|
+
/** Pane title (the item's name). */
|
|
21
|
+
title: ReactNode;
|
|
22
|
+
/** Optional secondary line under the title (type, id, status…). */
|
|
23
|
+
subtitle?: ReactNode;
|
|
24
|
+
/** Optional title icon, tinted with `iconColor`. */
|
|
25
|
+
icon?: IconLike;
|
|
26
|
+
iconColor?: string;
|
|
27
|
+
/** Desktop pane width (px). Mobile is always full-screen. Default 460. */
|
|
28
|
+
size?: number;
|
|
29
|
+
/** The body — the detail view or edit form for the item. */
|
|
30
|
+
content: ReactNode;
|
|
31
|
+
/** Optional sticky footer (primary actions), pinned below the scroll body. */
|
|
32
|
+
footer?: ReactNode;
|
|
33
|
+
};
|
|
34
|
+
export type DetailPaneApi = {
|
|
35
|
+
open: (descriptor: DetailDescriptor) => void;
|
|
36
|
+
close: () => void;
|
|
37
|
+
isOpen: boolean;
|
|
38
|
+
};
|
|
39
|
+
export declare function useDetailPane(): DetailPaneApi;
|
|
40
|
+
export type DetailPaneProps = {
|
|
41
|
+
children: ReactNode;
|
|
42
|
+
/** z-index for stacking — a pane opened over another overlay passes a
|
|
43
|
+
* higher value. Left to `SlideOver`'s own default otherwise. */
|
|
44
|
+
zIndex?: number;
|
|
45
|
+
};
|
|
46
|
+
export declare function DetailPane({ children, zIndex }: DetailPaneProps): import("react").JSX.Element;
|
|
47
|
+
//# sourceMappingURL=DetailPane.d.ts.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"DetailPane.d.ts","sourceRoot":"","sources":["../../src/product/DetailPane.tsx"],"names":[],"mappings":"AAEA;;;;;;;;;;;;;;;GAeG;AACH,OAAO,EAML,KAAK,SAAS,EACf,MAAM,OAAO,CAAA;AAKd,OAAO,EAAW,KAAK,QAAQ,EAAE,MAAM,SAAS,CAAA;AAEhD,MAAM,MAAM,gBAAgB,GAAG;IAC7B,oCAAoC;IACpC,KAAK,EAAE,SAAS,CAAA;IAChB,mEAAmE;IACnE,QAAQ,CAAC,EAAE,SAAS,CAAA;IACpB,oDAAoD;IACpD,IAAI,CAAC,EAAE,QAAQ,CAAA;IACf,SAAS,CAAC,EAAE,MAAM,CAAA;IAClB,0EAA0E;IAC1E,IAAI,CAAC,EAAE,MAAM,CAAA;IACb,4DAA4D;IAC5D,OAAO,EAAE,SAAS,CAAA;IAClB,8EAA8E;IAC9E,MAAM,CAAC,EAAE,SAAS,CAAA;CACnB,CAAA;AAED,MAAM,MAAM,aAAa,GAAG;IAC1B,IAAI,EAAE,CAAC,UAAU,EAAE,gBAAgB,KAAK,IAAI,CAAA;IAC5C,KAAK,EAAE,MAAM,IAAI,CAAA;IACjB,MAAM,EAAE,OAAO,CAAA;CAChB,CAAA;AAID,wBAAgB,aAAa,IAAI,aAAa,CAI7C;AAED,MAAM,MAAM,eAAe,GAAG;IAC5B,QAAQ,EAAE,SAAS,CAAA;IACnB;qEACiE;IACjE,MAAM,CAAC,EAAE,MAAM,CAAA;CAChB,CAAA;AAED,wBAAgB,UAAU,CAAC,EAAE,QAAQ,EAAE,MAAM,EAAE,EAAE,eAAe,+BAsD/D"}
|
|
@@ -0,0 +1,43 @@
|
|
|
1
|
+
'use client';
|
|
2
|
+
import { jsx as _jsx, jsxs as _jsxs } from "react/jsx-runtime";
|
|
3
|
+
/**
|
|
4
|
+
* DetailPane — the ONE reusable right-side pane for viewing or editing the
|
|
5
|
+
* details of an item. A product does NOT build its own pane: it writes a
|
|
6
|
+
* DESCRIPTOR (`{ title, subtitle?, icon?, content, footer? }`) and calls
|
|
7
|
+
* `useDetailPane().open(descriptor)`. The pane slides out from the right
|
|
8
|
+
* (full-screen on mobile) via `SlideOver`, so every "open item detail" looks
|
|
9
|
+
* and behaves identically (DRY).
|
|
10
|
+
*
|
|
11
|
+
* Rendered ONCE near the shell root; any module — a row, a list item, a
|
|
12
|
+
* pinned form — opens the same pane. Interactive content closes itself with
|
|
13
|
+
* `useDetailPane().close()`.
|
|
14
|
+
*
|
|
15
|
+
* The last descriptor stays mounted through the close transition, so the exit
|
|
16
|
+
* animates with its content (no flash of empty pane). Opening a new
|
|
17
|
+
* descriptor replaces it.
|
|
18
|
+
*/
|
|
19
|
+
import { createContext, useCallback, useContext, useMemo, useState, } from 'react';
|
|
20
|
+
import { Button, ScrollView, Text, XStack, YStack } from '@hanzo/gui';
|
|
21
|
+
import { X } from '@hanzogui/lucide-icons-2';
|
|
22
|
+
import { SlideOver } from './SlideOver.js';
|
|
23
|
+
import { asColor } from './color.js';
|
|
24
|
+
const Ctx = createContext(null);
|
|
25
|
+
export function useDetailPane() {
|
|
26
|
+
const ctx = useContext(Ctx);
|
|
27
|
+
if (!ctx)
|
|
28
|
+
throw new Error('useDetailPane must be used within <DetailPane>');
|
|
29
|
+
return ctx;
|
|
30
|
+
}
|
|
31
|
+
export function DetailPane({ children, zIndex }) {
|
|
32
|
+
const [isOpen, setIsOpen] = useState(false);
|
|
33
|
+
const [desc, setDesc] = useState(null);
|
|
34
|
+
const open = useCallback((descriptor) => {
|
|
35
|
+
setDesc(descriptor);
|
|
36
|
+
setIsOpen(true);
|
|
37
|
+
}, []);
|
|
38
|
+
const close = useCallback(() => setIsOpen(false), []);
|
|
39
|
+
const api = useMemo(() => ({ open, close, isOpen }), [open, close, isOpen]);
|
|
40
|
+
const Icon = desc?.icon;
|
|
41
|
+
return (_jsxs(Ctx.Provider, { value: api, children: [children, _jsxs(SlideOver, { open: isOpen, onClose: close, side: "right", size: desc?.size ?? 460, ariaLabel: typeof desc?.title === 'string' ? desc?.title : 'Details', zIndex: zIndex, children: [_jsxs(XStack, { items: "center", gap: "$2.5", px: "$4", height: 56, borderBottomWidth: 1, borderColor: "$borderColor", children: [Icon ? _jsx(Icon, { size: 18, color: desc?.iconColor ? asColor(desc.iconColor) : undefined }) : null, _jsxs(YStack, { flex: 1, minW: 0, children: [_jsx(Text, { fontSize: "$5", fontWeight: "700", color: "$color12", numberOfLines: 1, children: desc?.title }), desc?.subtitle !== undefined ? (_jsx(Text, { fontSize: "$2", color: "$color10", numberOfLines: 1, children: desc?.subtitle })) : null] }), _jsx(Button, { size: "$2", chromeless: true, icon: _jsx(X, { size: 18 }), onPress: close, "aria-label": "Close" })] }), _jsx(ScrollView, { flex: 1, minH: 0, children: _jsx(YStack, { p: "$4", gap: "$3", children: desc?.content }) }), desc?.footer !== undefined ? (_jsx(XStack, { px: "$4", py: "$3", gap: "$2", borderTopWidth: 1, borderColor: "$borderColor", bg: "$color1", children: desc?.footer })) : null] })] }));
|
|
42
|
+
}
|
|
43
|
+
//# sourceMappingURL=DetailPane.js.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"DetailPane.js","sourceRoot":"","sources":["../../src/product/DetailPane.tsx"],"names":[],"mappings":"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"}
|
|
@@ -0,0 +1,19 @@
|
|
|
1
|
+
"use strict";
|
|
2
|
+
Object.defineProperty(exports, "__esModule", { value: true });
|
|
3
|
+
exports.Fact = Fact;
|
|
4
|
+
const jsx_runtime_1 = require("react/jsx-runtime");
|
|
5
|
+
const gui_1 = require("@hanzo/gui");
|
|
6
|
+
const fonts_1 = require("../core/fonts.cjs");
|
|
7
|
+
/**
|
|
8
|
+
* Fact — one row of a property list: a label on the left, a value on the
|
|
9
|
+
* right, a hairline separator beneath. The read-only counterpart to `Field`'s
|
|
10
|
+
* editable row — a detail pane is a stack of these where a settings form is a
|
|
11
|
+
* stack of `Field`s.
|
|
12
|
+
*
|
|
13
|
+
* Written twice, near-identically, in two console detail drawers before
|
|
14
|
+
* either could find the other. This is the one definition; the wider of the
|
|
15
|
+
* two shapes won (a non-string `value` renders as given, not stringified).
|
|
16
|
+
*/
|
|
17
|
+
function Fact({ label, value, mono }) {
|
|
18
|
+
return ((0, jsx_runtime_1.jsxs)(gui_1.XStack, { justify: "space-between", items: "center", py: "$1.5", borderBottomWidth: 1, borderColor: "$borderColor", gap: "$3", children: [(0, jsx_runtime_1.jsx)(gui_1.Text, { fontSize: "$2", color: "$color11", children: label }), typeof value === 'string' ? ((0, jsx_runtime_1.jsx)(gui_1.Text, { fontSize: "$2", color: "$color12", fontWeight: "600", numberOfLines: 1, style: mono ? { fontFamily: fonts_1.fontMono } : undefined, children: value })) : (value)] }));
|
|
19
|
+
}
|
|
@@ -0,0 +1,23 @@
|
|
|
1
|
+
import type { ReactNode } from 'react';
|
|
2
|
+
export type FactProps = {
|
|
3
|
+
/** The row's left-hand label. */
|
|
4
|
+
label: string;
|
|
5
|
+
/** The row's right-hand value. A string renders in the value color and
|
|
6
|
+
* weight; anything else (a badge, a link, a stack of controls) renders as
|
|
7
|
+
* given. */
|
|
8
|
+
value: ReactNode;
|
|
9
|
+
/** Render a string value in the monospace face — an id, a hash, a path. */
|
|
10
|
+
mono?: boolean;
|
|
11
|
+
};
|
|
12
|
+
/**
|
|
13
|
+
* Fact — one row of a property list: a label on the left, a value on the
|
|
14
|
+
* right, a hairline separator beneath. The read-only counterpart to `Field`'s
|
|
15
|
+
* editable row — a detail pane is a stack of these where a settings form is a
|
|
16
|
+
* stack of `Field`s.
|
|
17
|
+
*
|
|
18
|
+
* Written twice, near-identically, in two console detail drawers before
|
|
19
|
+
* either could find the other. This is the one definition; the wider of the
|
|
20
|
+
* two shapes won (a non-string `value` renders as given, not stringified).
|
|
21
|
+
*/
|
|
22
|
+
export declare function Fact({ label, value, mono }: FactProps): import("react").JSX.Element;
|
|
23
|
+
//# sourceMappingURL=Fact.d.ts.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"Fact.d.ts","sourceRoot":"","sources":["../../src/product/Fact.tsx"],"names":[],"mappings":"AAAA,OAAO,KAAK,EAAE,SAAS,EAAE,MAAM,OAAO,CAAA;AAKtC,MAAM,MAAM,SAAS,GAAG;IACtB,iCAAiC;IACjC,KAAK,EAAE,MAAM,CAAA;IACb;;iBAEa;IACb,KAAK,EAAE,SAAS,CAAA;IAChB,2EAA2E;IAC3E,IAAI,CAAC,EAAE,OAAO,CAAA;CACf,CAAA;AAED;;;;;;;;;GASG;AACH,wBAAgB,IAAI,CAAC,EAAE,KAAK,EAAE,KAAK,EAAE,IAAI,EAAE,EAAE,SAAS,+BA4BrD"}
|
|
@@ -0,0 +1,17 @@
|
|
|
1
|
+
import { jsx as _jsx, jsxs as _jsxs } from "react/jsx-runtime";
|
|
2
|
+
import { Text, XStack } from '@hanzo/gui';
|
|
3
|
+
import { fontMono } from '../core/fonts.js';
|
|
4
|
+
/**
|
|
5
|
+
* Fact — one row of a property list: a label on the left, a value on the
|
|
6
|
+
* right, a hairline separator beneath. The read-only counterpart to `Field`'s
|
|
7
|
+
* editable row — a detail pane is a stack of these where a settings form is a
|
|
8
|
+
* stack of `Field`s.
|
|
9
|
+
*
|
|
10
|
+
* Written twice, near-identically, in two console detail drawers before
|
|
11
|
+
* either could find the other. This is the one definition; the wider of the
|
|
12
|
+
* two shapes won (a non-string `value` renders as given, not stringified).
|
|
13
|
+
*/
|
|
14
|
+
export function Fact({ label, value, mono }) {
|
|
15
|
+
return (_jsxs(XStack, { justify: "space-between", items: "center", py: "$1.5", borderBottomWidth: 1, borderColor: "$borderColor", gap: "$3", children: [_jsx(Text, { fontSize: "$2", color: "$color11", children: label }), typeof value === 'string' ? (_jsx(Text, { fontSize: "$2", color: "$color12", fontWeight: "600", numberOfLines: 1, style: mono ? { fontFamily: fontMono } : undefined, children: value })) : (value)] }));
|
|
16
|
+
}
|
|
17
|
+
//# sourceMappingURL=Fact.js.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"Fact.js","sourceRoot":"","sources":["../../src/product/Fact.tsx"],"names":[],"mappings":";AACA,OAAO,EAAE,IAAI,EAAE,MAAM,EAAE,MAAM,YAAY,CAAA;AAEzC,OAAO,EAAE,QAAQ,EAAE,MAAM,eAAe,CAAA;AAaxC;;;;;;;;;GASG;AACH,MAAM,UAAU,IAAI,CAAC,EAAE,KAAK,EAAE,KAAK,EAAE,IAAI,EAAa;IACpD,OAAO,CACL,MAAC,MAAM,IACL,OAAO,EAAC,eAAe,EACvB,KAAK,EAAC,QAAQ,EACd,EAAE,EAAC,MAAM,EACT,iBAAiB,EAAE,CAAC,EACpB,WAAW,EAAC,cAAc,EAC1B,GAAG,EAAC,IAAI,aAER,KAAC,IAAI,IAAC,QAAQ,EAAC,IAAI,EAAC,KAAK,EAAC,UAAU,YACjC,KAAK,GACD,EACN,OAAO,KAAK,KAAK,QAAQ,CAAC,CAAC,CAAC,CAC3B,KAAC,IAAI,IACH,QAAQ,EAAC,IAAI,EACb,KAAK,EAAC,UAAU,EAChB,UAAU,EAAC,KAAK,EAChB,aAAa,EAAE,CAAC,EAChB,KAAK,EAAE,IAAI,CAAC,CAAC,CAAC,EAAE,UAAU,EAAE,QAAQ,EAAE,CAAC,CAAC,CAAC,SAAS,YAEjD,KAAK,GACD,CACR,CAAC,CAAC,CAAC,CACF,KAAK,CACN,IACM,CACV,CAAA;AACH,CAAC"}
|