ab-nextjs-components 0.1.10 β 0.1.11
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/CHANGELOG.md +7 -0
- package/ab-flow-diagram/index.tsx +13 -2
- package/ab-flow-diagram/styles.module.css +27 -10
- package/package.json +1 -1
package/CHANGELOG.md
CHANGED
|
@@ -1,3 +1,10 @@
|
|
|
1
|
+
## 0.1.11 β 2026-10-15
|
|
2
|
+
|
|
3
|
+
* π **AbFlowDiagram: nodes no longer cover the header in small boxes.** At 390px wide the Live Playground's top node ("core") sat under the "Live Playground" header. With a header (title, live dot or caption) the root now gets `data-ab-header="true"`, and nodes + wires live in a stage that starts below the header band: `--ab-flow-diagram-inset-top` (default `2.75rem`, tunable). Node `x` / `y` stay 0β100 but now map onto that stage, and the wires share the same box so they still meet the nodes. Without a header the stage is the full card (unchanged)
|
|
4
|
+
* π **AbFlowDiagram nodes scale with the card:** `container-type: inline-size` on the root; node text, padding, radius and the hub glow use clamped `cqi` sizes (13px on a 760px card, 11px at 390px)
|
|
5
|
+
* πͺ **AbFlowDiagram: side nodes are never clipped** (Joseph: s04's `--ab-color-bronze` and s07's `reduced motion` were cut off at the card edge in a 390px box). The orbit now scales with the box. Each node is anchored at the same fraction of its own box as its position (`translate(-x%, -y%)` via `--ab-flow-node-x` / `-y`; `x = y = 50` is the old centring), so the outer ring pulls in by exactly the node's width, and the wire end stays inside the pill. Nodes + wires also sit inside a side margin, `--ab-flow-diagram-inset-x` (default `0.5rem`), and an over-long label ellipsises (`max-width: 100%`). Positions are clamped to 0β100 like the wires
|
|
6
|
+
* Tests: header flag, stage insets shared by nodes + wires, 390px geometry, clamped scaling, proportional anchoring + side margin, s04 / s07 orbit geometry at 390 / 760px Γ 276 / 380px. Checked in WebKit at 390px: "core" top 9px β 53px (header ends at 33px); no node overlaps the header or is clipped at 390 / 760px. After the orbit fix: s04 + s07 have no node clipped (x or y) or over the header at 390 / 760px wide Γ 276px / 380px / default-ratio heights (before: 5 nodes clipped at 390px, 2 at 760px)
|
|
7
|
+
|
|
1
8
|
## 0.1.10 β 2026-10-14
|
|
2
9
|
|
|
3
10
|
* **Motion comes from ab-nextjs-animations (>= 0.2.4, now a required peer):** no component CSS declares its own `transition`, `animation` or `@keyframes` any more. Each component imports the package stylesheet it needs:
|
|
@@ -73,6 +73,13 @@ export interface AbFlowDiagramProps {
|
|
|
73
73
|
children?: ReactNode; // π§© optional extra overlay (decorative)
|
|
74
74
|
}
|
|
75
75
|
|
|
76
|
+
// βοΈ 0β100 (same clamp as the wires, so a node and its wire end always agree)
|
|
77
|
+
const pct = (v: number): number => Math.min(100, Math.max(0, v));
|
|
78
|
+
|
|
79
|
+
/** π node position + proportional anchor (CSS keeps every node inside the stage, see styles.module.css) */
|
|
80
|
+
const nodeStyle = (n: AbFlowNode): CSSProperties =>
|
|
81
|
+
({ left: `${pct(n.x)}%`, top: `${pct(n.y)}%`, '--ab-flow-node-x': String(pct(n.x)), '--ab-flow-node-y': String(pct(n.y)) }) as CSSProperties;
|
|
82
|
+
|
|
76
83
|
/** π¨ Live Playground scene: SVG wires + HTML nodes, CSS-only motion, one accessible image. */
|
|
77
84
|
export function AbFlowDiagram(props: AbFlowDiagramProps): ReactElement {
|
|
78
85
|
// π§© props
|
|
@@ -88,6 +95,9 @@ export function AbFlowDiagram(props: AbFlowDiagramProps): ReactElement {
|
|
|
88
95
|
'--ab-wire-poster': String(100 - Math.min(1, Math.max(0, posterAt)) * 100), // πΌοΈ dashoffset at the poster frame
|
|
89
96
|
} as CSSProperties;
|
|
90
97
|
|
|
98
|
+
// π·οΈ is there a header row? (drives the header-safe stage inset in CSS)
|
|
99
|
+
const hasHeader = Boolean(title || live || caption);
|
|
100
|
+
|
|
91
101
|
return (
|
|
92
102
|
<figure
|
|
93
103
|
role="img" // βΏ the whole scene is ONE image
|
|
@@ -98,9 +108,10 @@ export function AbFlowDiagram(props: AbFlowDiagramProps): ReactElement {
|
|
|
98
108
|
data-active={String(active)} // βΆοΈ / βΈοΈ
|
|
99
109
|
data-ab-paused={String(!active)} // βΈοΈ ab-nextjs-animations pauses wires on inactive slides
|
|
100
110
|
data-variant={variant} // π
|
|
111
|
+
data-ab-header={String(hasHeader)} // π·οΈ header-safe stage: nodes + wires start below the header
|
|
101
112
|
>
|
|
102
113
|
{/* π·οΈ card header (decorative: alt already describes it) */}
|
|
103
|
-
{
|
|
114
|
+
{hasHeader ? (
|
|
104
115
|
<div className={styles.header} aria-hidden="true">
|
|
105
116
|
{title ? <span className={styles.title}>{title}</span> : null}
|
|
106
117
|
{live ? <span className={styles.live}><span className={styles.liveDot} />{typeof live === 'string' ? live : null}</span> : null}
|
|
@@ -126,7 +137,7 @@ export function AbFlowDiagram(props: AbFlowDiagramProps): ReactElement {
|
|
|
126
137
|
{/* π΅ nodes layer (HTML: crisp text, real fonts) */}
|
|
127
138
|
<div className={styles.nodes} aria-hidden="true">
|
|
128
139
|
{nodes.map((n) => (
|
|
129
|
-
<span key={n.id} className={styles.node} data-tone={n.tone ?? 'node'} style={
|
|
140
|
+
<span key={n.id} className={styles.node} data-tone={n.tone ?? 'node'} style={nodeStyle(n)}>
|
|
130
141
|
{n.icon ? <span className={styles.nodeIcon}>{n.icon}</span> : null}
|
|
131
142
|
<span>{n.label}</span>
|
|
132
143
|
</span>
|
|
@@ -47,6 +47,15 @@
|
|
|
47
47
|
background: var(--ab-color-surface-container, transparent); /* π¨ */
|
|
48
48
|
overflow: hidden; /* βοΈ */
|
|
49
49
|
color: var(--ab-color-on-surface, currentColor); /* π¨ */
|
|
50
|
+
container-type: inline-size; /* π¦ nodes scale with the card width (cqi units below) */
|
|
51
|
+
/* ποΈ stage insets (tunable): where nodes + wires may sit. Top is 0 unless a header renders (below) */
|
|
52
|
+
--ab-flow-diagram-stage-top: 0px;
|
|
53
|
+
--ab-flow-diagram-stage-x: var(--ab-flow-diagram-inset-x, 0.5rem); /* βοΈ side margin: nodes never touch the card edge */
|
|
54
|
+
}
|
|
55
|
+
/* π·οΈ header-safe stage: with a title / live dot / caption, nodes + wires start BELOW the header band, so a
|
|
56
|
+
* node near the top (e.g. "core" at 390px) can't cover the header. Override with --ab-flow-diagram-inset-top */
|
|
57
|
+
.root[data-ab-header='true'] {
|
|
58
|
+
--ab-flow-diagram-stage-top: var(--ab-flow-diagram-inset-top, 2.75rem); /* π 0.875rem header top + ~1.25rem row + gap */
|
|
50
59
|
}
|
|
51
60
|
.root[data-variant='compact'] {
|
|
52
61
|
aspect-ratio: auto; /* π */
|
|
@@ -78,9 +87,9 @@
|
|
|
78
87
|
/* γ°οΈ wires layer */
|
|
79
88
|
.wires {
|
|
80
89
|
position: absolute; /* π */
|
|
81
|
-
inset: 0; /* π
|
|
82
|
-
width: 100
|
|
83
|
-
height: 100
|
|
90
|
+
inset: var(--ab-flow-diagram-stage-top) var(--ab-flow-diagram-stage-x) 0; /* π the stage (below the header, inside the side margins) */
|
|
91
|
+
width: calc(100% - 2 * var(--ab-flow-diagram-stage-x)); /* βοΈ same box as .nodes */
|
|
92
|
+
height: calc(100% - var(--ab-flow-diagram-stage-top)); /* βοΈ same box as .nodes, so wires meet the nodes */
|
|
84
93
|
overflow: visible; /* π« clip */
|
|
85
94
|
}
|
|
86
95
|
.wire,
|
|
@@ -101,25 +110,33 @@
|
|
|
101
110
|
}
|
|
102
111
|
|
|
103
112
|
/* π΅ nodes layer */
|
|
104
|
-
.nodes { position: absolute; inset: 0; } /* π */
|
|
113
|
+
.nodes { position: absolute; inset: var(--ab-flow-diagram-stage-top) var(--ab-flow-diagram-stage-x) 0; } /* π same stage as .wires */
|
|
105
114
|
.node {
|
|
106
115
|
position: absolute; /* π x/y */
|
|
107
|
-
|
|
116
|
+
/* π― orbit that scales with the box: each node is anchored at the SAME fraction of its own box as its
|
|
117
|
+
* position in the stage (x = 8 β 8% of the pill sits left of the point, x = 92 β 92%). So the outer edge
|
|
118
|
+
* of the orbit pulls in by exactly the node's width: a side node can never cross the card edge, at any
|
|
119
|
+
* box size, and the wire end (the point) is always inside the pill. x = y = 50 is the old centring. */
|
|
120
|
+
transform: translate(calc(var(--ab-flow-node-x, 50) * -1%), calc(var(--ab-flow-node-y, 50) * -1%));
|
|
121
|
+
max-width: 100%; /* π an over-long label can't be wider than the stageβ¦ */
|
|
122
|
+
overflow: hidden; /* βοΈ β¦it ellipsises instead */
|
|
123
|
+
text-overflow: ellipsis; /* β¦ */
|
|
108
124
|
display: inline-flex; /* π */
|
|
109
125
|
align-items: center; /* βοΈ */
|
|
110
126
|
gap: 0.375rem; /* π§± */
|
|
111
|
-
|
|
112
|
-
|
|
127
|
+
/* π scales with the card (cqi = 1% of its width): 760px card β 13px text, 390px β 11px; clamped both ways */
|
|
128
|
+
padding: clamp(0.25rem, 0.8cqi, 0.375rem) clamp(0.4375rem, 1.4cqi, 0.625rem); /* π§± */
|
|
129
|
+
border-radius: clamp(0.5rem, 1.4cqi, 0.625rem); /* π² */
|
|
113
130
|
border: 1px solid var(--ab-color-outline-variant, rgb(0 0 0 / 0.12)); /* ποΈ */
|
|
114
131
|
background: var(--ab-color-surface, #fff); /* π¨ */
|
|
115
|
-
font-size: 0.8125rem; /* π‘ */
|
|
132
|
+
font-size: clamp(0.6875rem, 1.75cqi, 0.8125rem); /* π‘ */
|
|
116
133
|
white-space: nowrap; /* π« wrap */
|
|
117
134
|
}
|
|
118
135
|
.node[data-tone='hub'] {
|
|
119
|
-
padding: 0.625rem 0.875rem; /* π§± bigger */
|
|
136
|
+
padding: clamp(0.4375rem, 1.4cqi, 0.625rem) clamp(0.625rem, 1.9cqi, 0.875rem); /* π§± bigger (scales too) */
|
|
120
137
|
border-color: var(--ab-color-bronze, #A67C52); /* π₯ */
|
|
121
138
|
font-weight: 700; /* πͺ */
|
|
122
|
-
box-shadow: 0 0 0 6px color-mix(in srgb, var(--ab-color-bronze, #A67C52) 12%, transparent); /* β¨ glow */
|
|
139
|
+
box-shadow: 0 0 0 clamp(3px, 0.8cqi, 6px) color-mix(in srgb, var(--ab-color-bronze, #A67C52) 12%, transparent); /* β¨ glow */
|
|
123
140
|
}
|
|
124
141
|
.node[data-tone='accent'] { color: var(--ab-color-bronze-text, #8A6440); } /* βΏ */
|
|
125
142
|
.nodeIcon { display: inline-flex; width: 1.125rem; height: 1.125rem; } /* πΌοΈ */
|
package/package.json
CHANGED
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
{
|
|
2
2
|
"name": "ab-nextjs-components",
|
|
3
|
-
"version": "0.1.
|
|
3
|
+
"version": "0.1.11",
|
|
4
4
|
"description": "π A lightweight collection of server & client React components created by Abraham Ukachi, and optimized for Next.js applications π.",
|
|
5
5
|
"type": "module",
|
|
6
6
|
"main": "index.ts",
|