@nadicodeai/ui 12.1.150 → 12.1.151
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.
|
@@ -25,6 +25,13 @@ export type HivePoint = {
|
|
|
25
25
|
x: number;
|
|
26
26
|
y: number;
|
|
27
27
|
};
|
|
28
|
+
/** A box in the scene's pixels, from its top left corner. */
|
|
29
|
+
export type HiveBox = {
|
|
30
|
+
left: number;
|
|
31
|
+
top: number;
|
|
32
|
+
right: number;
|
|
33
|
+
bottom: number;
|
|
34
|
+
};
|
|
28
35
|
/** Where the work comes from and goes to in the picture, in the scene's pixels. */
|
|
29
36
|
export type HiveWork = {
|
|
30
37
|
senders: readonly HivePoint[];
|
|
@@ -41,13 +48,16 @@ export type HiveSceneProps = Omit<React.ComponentProps<"div">, "children"> & {
|
|
|
41
48
|
src: string;
|
|
42
49
|
label: string;
|
|
43
50
|
};
|
|
44
|
-
/**
|
|
51
|
+
/**
|
|
52
|
+
* The app's picture, placed by the app's own stylesheet, which keeps it clear of the words by
|
|
53
|
+
* the width the scene sets on itself as `--hive-words-width`.
|
|
54
|
+
*/
|
|
45
55
|
picture?: React.ReactNode;
|
|
46
|
-
/**
|
|
47
|
-
|
|
48
|
-
|
|
49
|
-
|
|
50
|
-
|
|
56
|
+
/**
|
|
57
|
+
* The picture's people, so the work reaches them: `pictures` are the boxes the picture's
|
|
58
|
+
* elements are drawn in now, in their order, an element not drawn as an empty box.
|
|
59
|
+
*/
|
|
60
|
+
work?: (pictures: readonly HiveBox[]) => HiveWork;
|
|
51
61
|
/** Window chrome the scene must carry, such as a drag region. */
|
|
52
62
|
chrome?: React.ReactNode;
|
|
53
63
|
/** What `loading` is waiting for, read by assistive technology. */
|
|
@@ -62,7 +72,8 @@ export type HiveSceneProps = Omit<React.ComponentProps<"div">, "children"> & {
|
|
|
62
72
|
* @instead Nadia's entry screens are `EntryScene`. A product page never stands on a scene.
|
|
63
73
|
* @behaviour `join` puts the words in the hexagon's middle, `loading` draws the orbs in with no
|
|
64
74
|
* words, `still` shows no Agent and no work. Only the orbs and the particles move; reduced motion
|
|
65
|
-
* stops both. Black in every theme.
|
|
75
|
+
* stops both. Black in every theme. The scene sets the width its words are drawn at on itself as
|
|
76
|
+
* `--hive-words-width`, so the app's picture keeps clear of them, and draws no honeycomb near them.
|
|
66
77
|
* @words The words are the screen's own: a title, a line, one action. The logo's label names
|
|
67
78
|
* Alveare.
|
|
68
79
|
* @access The canvases are hidden; the logo's image is named by its label. In `loading` the scene
|
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"hive-scene.d.ts","sourceRoot":"","sources":["../../src/components/hive-scene.tsx"],"names":[],"mappings":"AAEA,OAAO,KAAK,KAAK,MAAM,OAAO,CAAC;AAK/B;;;;;;;;;;;;;;;;;;;;;GAqBG;AAEH,MAAM,MAAM,SAAS,GAAG;IAAE,CAAC,EAAE,MAAM,CAAC;IAAC,CAAC,EAAE,MAAM,CAAA;CAAE,CAAC;AAEjD,mFAAmF;AACnF,MAAM,MAAM,QAAQ,GAAG;IACrB,OAAO,EAAE,SAAS,SAAS,EAAE,CAAC;IAC9B,SAAS,EAAE,SAAS,SAAS,EAAE,CAAC;CACjC,CAAC;AAEF,MAAM,MAAM,aAAa,GAAG,MAAM,GAAG,SAAS,GAAG,OAAO,CAAC;AAEzD,MAAM,MAAM,eAAe,GAAG,SAAS,GAAG,OAAO,CAAC;AAElD,MAAM,MAAM,cAAc,GAAG,IAAI,CAAC,KAAK,CAAC,cAAc,CAAC,KAAK,CAAC,EAAE,UAAU,CAAC,GAAG;IAC3E,IAAI,EAAE,aAAa,CAAC;IACpB,qFAAqF;IACrF,MAAM,CAAC,EAAE,eAAe,CAAC;IACzB,kFAAkF;IAClF,IAAI,EAAE;QAAE,GAAG,EAAE,MAAM,CAAC;QAAC,KAAK,EAAE,MAAM,CAAA;KAAE,CAAC;IACrC
|
|
1
|
+
{"version":3,"file":"hive-scene.d.ts","sourceRoot":"","sources":["../../src/components/hive-scene.tsx"],"names":[],"mappings":"AAEA,OAAO,KAAK,KAAK,MAAM,OAAO,CAAC;AAK/B;;;;;;;;;;;;;;;;;;;;;GAqBG;AAEH,MAAM,MAAM,SAAS,GAAG;IAAE,CAAC,EAAE,MAAM,CAAC;IAAC,CAAC,EAAE,MAAM,CAAA;CAAE,CAAC;AAEjD,6DAA6D;AAC7D,MAAM,MAAM,OAAO,GAAG;IAAE,IAAI,EAAE,MAAM,CAAC;IAAC,GAAG,EAAE,MAAM,CAAC;IAAC,KAAK,EAAE,MAAM,CAAC;IAAC,MAAM,EAAE,MAAM,CAAA;CAAE,CAAC;AAEnF,mFAAmF;AACnF,MAAM,MAAM,QAAQ,GAAG;IACrB,OAAO,EAAE,SAAS,SAAS,EAAE,CAAC;IAC9B,SAAS,EAAE,SAAS,SAAS,EAAE,CAAC;CACjC,CAAC;AAEF,MAAM,MAAM,aAAa,GAAG,MAAM,GAAG,SAAS,GAAG,OAAO,CAAC;AAEzD,MAAM,MAAM,eAAe,GAAG,SAAS,GAAG,OAAO,CAAC;AAElD,MAAM,MAAM,cAAc,GAAG,IAAI,CAAC,KAAK,CAAC,cAAc,CAAC,KAAK,CAAC,EAAE,UAAU,CAAC,GAAG;IAC3E,IAAI,EAAE,aAAa,CAAC;IACpB,qFAAqF;IACrF,MAAM,CAAC,EAAE,eAAe,CAAC;IACzB,kFAAkF;IAClF,IAAI,EAAE;QAAE,GAAG,EAAE,MAAM,CAAC;QAAC,KAAK,EAAE,MAAM,CAAA;KAAE,CAAC;IACrC;;;OAGG;IACH,OAAO,CAAC,EAAE,KAAK,CAAC,SAAS,CAAC;IAC1B;;;OAGG;IACH,IAAI,CAAC,EAAE,CAAC,QAAQ,EAAE,SAAS,OAAO,EAAE,KAAK,QAAQ,CAAC;IAClD,iEAAiE;IACjE,MAAM,CAAC,EAAE,KAAK,CAAC,SAAS,CAAC;IACzB,mEAAmE;IACnE,KAAK,CAAC,EAAE,MAAM,CAAC;IACf,QAAQ,CAAC,EAAE,KAAK,CAAC,SAAS,CAAC;CAC5B,CAAC;AA4LF;;;;;;;;;;;;;;GAcG;AACH,iBAAS,SAAS,CAAC,EACjB,IAAI,EACJ,MAAkB,EAClB,IAAI,EACJ,OAAO,EACP,IAAI,EACJ,MAAM,EACN,KAAK,EACL,SAAS,EACT,QAAQ,EACR,GAAG,KAAK,EACT,EAAE,cAAc,qBA4QhB;AAED,2DAA2D;AAC3D,iBAAS,SAAS,CAAC,EAAE,QAAQ,EAAE,EAAE,EAAE,EAAE;IAAE,QAAQ,EAAE,KAAK,CAAC,SAAS,CAAC;IAAC,EAAE,CAAC,EAAE,MAAM,CAAA;CAAE,qBAM9E;AAED,iEAAiE;AACjE,iBAAS,QAAQ,CAAC,EAChB,QAAQ,EACR,EAAE,EACF,IAAa,GACd,EAAE;IACD,QAAQ,EAAE,KAAK,CAAC,SAAS,CAAC;IAC1B,EAAE,CAAC,EAAE,MAAM,CAAC;IACZ,IAAI,CAAC,EAAE,MAAM,GAAG,OAAO,CAAC;CACzB,qBAMA;AAED,OAAO,EAAE,QAAQ,EAAE,SAAS,EAAE,SAAS,EAAE,CAAC"}
|
|
@@ -111,7 +111,7 @@ const COMB_CLUSTERS = [
|
|
|
111
111
|
],
|
|
112
112
|
},
|
|
113
113
|
];
|
|
114
|
-
function drawComb(canvas, width, height) {
|
|
114
|
+
function drawComb(canvas, width, height, words) {
|
|
115
115
|
const context = sizeCanvas(canvas, width, height);
|
|
116
116
|
if (!context)
|
|
117
117
|
return;
|
|
@@ -120,14 +120,22 @@ function drawComb(canvas, width, height) {
|
|
|
120
120
|
// Pointy-top cells in axial coordinates: q along the row, r down the rows.
|
|
121
121
|
// One path per cluster, stroked once, so an edge two cells share is one line.
|
|
122
122
|
const across = Math.sqrt(3) * COMB_RADIUS;
|
|
123
|
+
const reach = COMB_RADIUS + WORDS_GAP;
|
|
123
124
|
for (const cluster of COMB_CLUSTERS) {
|
|
125
|
+
const centres = cluster.cells.map(([q, r]) => ({
|
|
126
|
+
x: cluster.x * width + across * (q + r / 2),
|
|
127
|
+
y: cluster.y * height + 1.5 * COMB_RADIUS * r,
|
|
128
|
+
}));
|
|
129
|
+
const nearWords = words &&
|
|
130
|
+
centres.some(({ x, y }) => x + reach > words.left &&
|
|
131
|
+
x - reach < words.right &&
|
|
132
|
+
y + reach > words.top &&
|
|
133
|
+
y - reach < words.bottom);
|
|
134
|
+
if (nearWords)
|
|
135
|
+
continue;
|
|
124
136
|
context.globalAlpha = cluster.alpha;
|
|
125
137
|
context.beginPath();
|
|
126
|
-
for (const
|
|
127
|
-
const centre = {
|
|
128
|
-
x: cluster.x * width + across * (q + r / 2),
|
|
129
|
-
y: cluster.y * height + 1.5 * COMB_RADIUS * r,
|
|
130
|
-
};
|
|
138
|
+
for (const centre of centres) {
|
|
131
139
|
for (let k = 0; k <= 6; k += 1) {
|
|
132
140
|
const { x, y } = corner(k % 6, centre, COMB_RADIUS);
|
|
133
141
|
if (k === 0)
|
|
@@ -158,7 +166,8 @@ function pick(items) {
|
|
|
158
166
|
* @instead Nadia's entry screens are `EntryScene`. A product page never stands on a scene.
|
|
159
167
|
* @behaviour `join` puts the words in the hexagon's middle, `loading` draws the orbs in with no
|
|
160
168
|
* words, `still` shows no Agent and no work. Only the orbs and the particles move; reduced motion
|
|
161
|
-
* stops both. Black in every theme.
|
|
169
|
+
* stops both. Black in every theme. The scene sets the width its words are drawn at on itself as
|
|
170
|
+
* `--hive-words-width`, so the app's picture keeps clear of them, and draws no honeycomb near them.
|
|
162
171
|
* @words The words are the screen's own: a title, a line, one action. The logo's label names
|
|
163
172
|
* Alveare.
|
|
164
173
|
* @access The canvases are hidden; the logo's image is named by its label. In `loading` the scene
|
|
@@ -168,6 +177,7 @@ function HiveScene({ mode, column = "default", logo, picture, work, chrome, labe
|
|
|
168
177
|
const sceneRef = React.useRef(null);
|
|
169
178
|
const combRef = React.useRef(null);
|
|
170
179
|
const flowRef = React.useRef(null);
|
|
180
|
+
const picturesRef = React.useRef(null);
|
|
171
181
|
const orbRefs = React.useRef([]);
|
|
172
182
|
const holderRefs = React.useRef([]);
|
|
173
183
|
// The words' box, kept as state so the scene places the orbs again when it appears.
|
|
@@ -208,12 +218,13 @@ function HiveScene({ mode, column = "default", logo, picture, work, chrome, labe
|
|
|
208
218
|
let height = 0;
|
|
209
219
|
let context = null;
|
|
210
220
|
let seats = [];
|
|
221
|
+
let bounds = scene.getBoundingClientRect();
|
|
211
222
|
const place = () => {
|
|
212
223
|
width = scene.clientWidth;
|
|
213
224
|
height = scene.clientHeight;
|
|
214
225
|
const centre = { x: width / 2, y: height / 2 };
|
|
215
226
|
const radius = cellRadius(width, height) * (mode === "loading" ? 0.62 : 1);
|
|
216
|
-
|
|
227
|
+
bounds = scene.getBoundingClientRect();
|
|
217
228
|
const box = wordsColumn?.getBoundingClientRect();
|
|
218
229
|
const words = box?.width
|
|
219
230
|
? {
|
|
@@ -223,6 +234,7 @@ function HiveScene({ mode, column = "default", logo, picture, work, chrome, labe
|
|
|
223
234
|
bottom: box.bottom - bounds.top,
|
|
224
235
|
}
|
|
225
236
|
: null;
|
|
237
|
+
scene.style.setProperty("--hive-words-width", `${words ? words.right - words.left : 0}px`);
|
|
226
238
|
seats = still
|
|
227
239
|
? []
|
|
228
240
|
: AGENTS.map((agent, index) => clearOfWords(corner(index, centre, radius), agent.size, words, { width, height }));
|
|
@@ -236,7 +248,7 @@ function HiveScene({ mode, column = "default", logo, picture, work, chrome, labe
|
|
|
236
248
|
holder.style.left = `${seat.x}px`;
|
|
237
249
|
holder.style.top = `${seat.y}px`;
|
|
238
250
|
});
|
|
239
|
-
drawComb(comb, width, height);
|
|
251
|
+
drawComb(comb, width, height, words);
|
|
240
252
|
context = sizeCanvas(flow, width, height);
|
|
241
253
|
};
|
|
242
254
|
const observeLayout = (onLayout) => {
|
|
@@ -266,7 +278,16 @@ function HiveScene({ mode, column = "default", logo, picture, work, chrome, labe
|
|
|
266
278
|
const others = seats.filter((other) => other !== null && other !== seat);
|
|
267
279
|
const neighbour = (source + 1 + (Math.random() < 0.5 ? 0 : 4)) % AGENTS.length;
|
|
268
280
|
const next = seats[neighbour] ?? pick(others);
|
|
269
|
-
const
|
|
281
|
+
const pictures = Array.from(picturesRef.current?.children ?? [], (element) => {
|
|
282
|
+
const drawn = element.getBoundingClientRect();
|
|
283
|
+
return {
|
|
284
|
+
left: drawn.left - bounds.left,
|
|
285
|
+
top: drawn.top - bounds.top,
|
|
286
|
+
right: drawn.right - bounds.left,
|
|
287
|
+
bottom: drawn.bottom - bounds.top,
|
|
288
|
+
};
|
|
289
|
+
});
|
|
290
|
+
const people = workRef.current?.(pictures);
|
|
270
291
|
const sender = people ? pick(people.senders) : undefined;
|
|
271
292
|
const receiver = people ? pick(people.receivers) : undefined;
|
|
272
293
|
const roll = Math.random();
|
|
@@ -368,7 +389,7 @@ function HiveScene({ mode, column = "default", logo, picture, work, chrome, labe
|
|
|
368
389
|
reduced.removeEventListener("change", play);
|
|
369
390
|
};
|
|
370
391
|
}, [mode, still, wordsColumn]);
|
|
371
|
-
return (_jsxs("div", { ...props, className: cn("nc-hive dark", className), "data-mode": mode, "data-slot": "hive-scene", ref: sceneRef, ...(mode === "loading" ? { "aria-label": label, role: "status" } : {}), children: [chrome, _jsx("img", { alt: logo.label, className: "nc-hive-logo", "data-slot": "hive-logo", src: logo.src }), picture, _jsx("canvas", { "aria-hidden": "true", className: "nc-hive-comb", ref: combRef }), _jsx("canvas", { "aria-hidden": "true", className: "nc-hive-flow", ref: flowRef }), still
|
|
392
|
+
return (_jsxs("div", { ...props, className: cn("nc-hive dark", className), "data-mode": mode, "data-slot": "hive-scene", ref: sceneRef, ...(mode === "loading" ? { "aria-label": label, role: "status" } : {}), children: [chrome, _jsx("img", { alt: logo.label, className: "nc-hive-logo", "data-slot": "hive-logo", src: logo.src }), _jsx("div", { className: "nc-hive-pictures", ref: picturesRef, children: picture }), _jsx("canvas", { "aria-hidden": "true", className: "nc-hive-comb", ref: combRef }), _jsx("canvas", { "aria-hidden": "true", className: "nc-hive-flow", ref: flowRef }), still
|
|
372
393
|
? null
|
|
373
394
|
: AGENTS.map((agent, index) => (_jsx("div", { "aria-hidden": "true", className: "nc-hive-agent", "data-slot": "hive-agent", "data-size": agent.size, ref: (holder) => {
|
|
374
395
|
holderRefs.current[index] = holder;
|
|
@@ -1759,7 +1759,7 @@ export const USAGE = [
|
|
|
1759
1759
|
summary: "Alveare's entry scene: its picture, its logo and six Agent orbs around the words.",
|
|
1760
1760
|
when: "Alveare's entry screens, on its desktop and on Alveare Server: joining, loading, a failure.",
|
|
1761
1761
|
instead: "Nadia's entry screens are `EntryScene`. A product page never stands on a scene.",
|
|
1762
|
-
behaviour: "`join` puts the words in the hexagon's middle, `loading` draws the orbs in with no words, `still` shows no Agent and no work. Only the orbs and the particles move; reduced motion stops both. Black in every theme.",
|
|
1762
|
+
behaviour: "`join` puts the words in the hexagon's middle, `loading` draws the orbs in with no words, `still` shows no Agent and no work. Only the orbs and the particles move; reduced motion stops both. Black in every theme. The scene sets the width its words are drawn at on itself as `--hive-words-width`, so the app's picture keeps clear of them, and draws no honeycomb near them.",
|
|
1763
1763
|
words: "The words are the screen's own: a title, a line, one action. The logo's label names Alveare.",
|
|
1764
1764
|
access: 'The canvases are hidden; the logo\'s image is named by its label. In `loading` the scene is `role="status"` named by `label`; otherwise the words and their action are the reading.',
|
|
1765
1765
|
},
|
|
@@ -636,6 +636,12 @@
|
|
|
636
636
|
background: var(--nc-identity-ink);
|
|
637
637
|
color: var(--nc-ink);
|
|
638
638
|
color-scheme: dark;
|
|
639
|
+
--hive-column-width: min(20rem, 80vw);
|
|
640
|
+
--hive-words-width: var(--hive-column-width);
|
|
641
|
+
}
|
|
642
|
+
|
|
643
|
+
.nc-hive-pictures {
|
|
644
|
+
display: contents;
|
|
639
645
|
}
|
|
640
646
|
|
|
641
647
|
/*
|
|
@@ -718,7 +724,7 @@
|
|
|
718
724
|
display: grid;
|
|
719
725
|
justify-items: stretch;
|
|
720
726
|
gap: var(--nc-md);
|
|
721
|
-
width:
|
|
727
|
+
width: var(--hive-column-width);
|
|
722
728
|
text-align: center;
|
|
723
729
|
text-wrap-style: balance;
|
|
724
730
|
}
|
package/package.json
CHANGED
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
{
|
|
2
2
|
"name": "@nadicodeai/ui",
|
|
3
|
-
"version": "12.1.
|
|
3
|
+
"version": "12.1.151",
|
|
4
4
|
"type": "module",
|
|
5
5
|
"publishConfig": {
|
|
6
6
|
"access": "public"
|
|
@@ -84,7 +84,7 @@
|
|
|
84
84
|
"@base-ui/react": "^1.9.0",
|
|
85
85
|
"@iconify-icons/logos": "^2.0.3",
|
|
86
86
|
"@iconify/react": "^6.0.2",
|
|
87
|
-
"@nadicodeai/design-system": "12.1.
|
|
87
|
+
"@nadicodeai/design-system": "12.1.151",
|
|
88
88
|
"@tanstack/react-table": "^9.3.1",
|
|
89
89
|
"@vgpu/wgsl": "0.6.0",
|
|
90
90
|
"class-variance-authority": "^0.7.1",
|