@gridland/demo 0.2.12 → 0.2.13
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/bin/cli.mjs +21 -3
- package/dist/run.js +44 -32
- package/package.json +1 -1
package/bin/cli.mjs
CHANGED
|
@@ -1,5 +1,6 @@
|
|
|
1
1
|
#!/usr/bin/env node
|
|
2
2
|
import { readFileSync } from "node:fs";
|
|
3
|
+
import { execSync, spawnSync } from "node:child_process";
|
|
3
4
|
import { fileURLToPath } from "node:url";
|
|
4
5
|
import { dirname, join } from "node:path";
|
|
5
6
|
|
|
@@ -17,7 +18,7 @@ if (!name || name === "--help" || name === "-h") {
|
|
|
17
18
|
console.log(` ${d}`);
|
|
18
19
|
}
|
|
19
20
|
console.log("\nExamples:");
|
|
20
|
-
console.log("
|
|
21
|
+
console.log(" bunx @gridland/demo ascii");
|
|
21
22
|
console.log(" bunx @gridland/demo gradient");
|
|
22
23
|
process.exit(name ? 0 : 1);
|
|
23
24
|
}
|
|
@@ -28,5 +29,22 @@ if (!AVAILABLE_DEMOS.includes(name)) {
|
|
|
28
29
|
process.exit(1);
|
|
29
30
|
}
|
|
30
31
|
|
|
31
|
-
|
|
32
|
-
|
|
32
|
+
// @opentui/core uses bun:ffi for the native terminal renderer, so we must run under bun
|
|
33
|
+
let hasBun = false;
|
|
34
|
+
try {
|
|
35
|
+
execSync("bun --version", { stdio: "ignore" });
|
|
36
|
+
hasBun = true;
|
|
37
|
+
} catch {}
|
|
38
|
+
|
|
39
|
+
if (!hasBun) {
|
|
40
|
+
console.error("Error: bun is required to run gridland demos.");
|
|
41
|
+
console.error("Install it with: curl -fsSL https://bun.sh/install | bash");
|
|
42
|
+
console.error("\nThen run: bunx @gridland/demo " + name);
|
|
43
|
+
process.exit(1);
|
|
44
|
+
}
|
|
45
|
+
|
|
46
|
+
const runPath = join(__dirname, "../dist/run.js");
|
|
47
|
+
const { status } = spawnSync("bun", ["-e", `import("${runPath}").then(m => m.runDemo("${name}"))`], {
|
|
48
|
+
stdio: "inherit",
|
|
49
|
+
});
|
|
50
|
+
process.exit(status ?? 1);
|
package/dist/run.js
CHANGED
|
@@ -299,11 +299,10 @@ function SelectInput({
|
|
|
299
299
|
list.push(item);
|
|
300
300
|
grouped.set(group, list);
|
|
301
301
|
}
|
|
302
|
-
let
|
|
302
|
+
let first = true;
|
|
303
303
|
for (const [group, groupItems] of grouped) {
|
|
304
|
-
if (
|
|
305
|
-
|
|
306
|
-
}
|
|
304
|
+
if (!first) rows.push({ type: "separator" });
|
|
305
|
+
first = false;
|
|
307
306
|
if (group) {
|
|
308
307
|
rows.push({ type: "group", label: group });
|
|
309
308
|
}
|
|
@@ -312,7 +311,6 @@ function SelectInput({
|
|
|
312
311
|
selectable.push({ item, index });
|
|
313
312
|
index++;
|
|
314
313
|
}
|
|
315
|
-
groupIndex++;
|
|
316
314
|
}
|
|
317
315
|
return { flatRows: rows, selectableItems: selectable };
|
|
318
316
|
}, [items]);
|
|
@@ -480,6 +478,7 @@ function MultiSelect({
|
|
|
480
478
|
enableClear = true,
|
|
481
479
|
highlightColor,
|
|
482
480
|
checkboxColor,
|
|
481
|
+
allowEmpty = false,
|
|
483
482
|
onSubmit,
|
|
484
483
|
useKeyboard: useKeyboard3
|
|
485
484
|
}) {
|
|
@@ -496,10 +495,8 @@ function MultiSelect({
|
|
|
496
495
|
selected: new Set(isControlled ? controlledSelected : defaultSelected),
|
|
497
496
|
submitted: false
|
|
498
497
|
});
|
|
499
|
-
const
|
|
500
|
-
|
|
501
|
-
[isControlled, controlledSelected, state.selected]
|
|
502
|
-
);
|
|
498
|
+
const cursorRef = useRef2(0);
|
|
499
|
+
const currentSelected = isControlled ? new Set(controlledSelected) : state.selected;
|
|
503
500
|
const { flatRows, selectableItems } = useMemo2(() => {
|
|
504
501
|
const rows = [];
|
|
505
502
|
const selectable = [];
|
|
@@ -511,11 +508,10 @@ function MultiSelect({
|
|
|
511
508
|
list.push(item);
|
|
512
509
|
grouped.set(group, list);
|
|
513
510
|
}
|
|
514
|
-
let
|
|
511
|
+
let first = true;
|
|
515
512
|
for (const [group, groupItems] of grouped) {
|
|
516
|
-
if (
|
|
517
|
-
|
|
518
|
-
}
|
|
513
|
+
if (!first) rows.push({ type: "separator" });
|
|
514
|
+
first = false;
|
|
519
515
|
if (group) {
|
|
520
516
|
rows.push({ type: "group", label: group });
|
|
521
517
|
}
|
|
@@ -524,10 +520,12 @@ function MultiSelect({
|
|
|
524
520
|
selectable.push({ item, index });
|
|
525
521
|
index++;
|
|
526
522
|
}
|
|
527
|
-
groupIndex++;
|
|
528
523
|
}
|
|
529
524
|
return { flatRows: rows, selectableItems: selectable };
|
|
530
525
|
}, [items]);
|
|
526
|
+
const hasSubmitRow = allowEmpty || currentSelected.size > 0;
|
|
527
|
+
const totalPositions = selectableItems.length + (hasSubmitRow ? 1 : 0);
|
|
528
|
+
const isOnSubmit = hasSubmitRow && state.cursor === selectableItems.length;
|
|
531
529
|
const visibleCount = limit ?? VISIBLE2;
|
|
532
530
|
const cursorRowIndex = flatRows.findIndex((r) => r.type === "item" && r.index === state.cursor);
|
|
533
531
|
const scrollOffset = Math.max(0, Math.min(cursorRowIndex - Math.floor(visibleCount / 2), flatRows.length - visibleCount));
|
|
@@ -542,28 +540,38 @@ function MultiSelect({
|
|
|
542
540
|
const diamondColor = invalid ? theme.error : disabled ? theme.muted : theme.accent;
|
|
543
541
|
useKeyboard3?.((event) => {
|
|
544
542
|
if (state.submitted || disabled) return;
|
|
543
|
+
const move = (direction) => {
|
|
544
|
+
let next = cursorRef.current + direction;
|
|
545
|
+
if (next < 0) next = totalPositions - 1;
|
|
546
|
+
if (next >= totalPositions) next = 0;
|
|
547
|
+
cursorRef.current = next;
|
|
548
|
+
dispatch({ type: "MOVE", direction, max: totalPositions });
|
|
549
|
+
};
|
|
545
550
|
if (event.name === "up" || event.name === "k") {
|
|
546
|
-
|
|
551
|
+
move(-1);
|
|
547
552
|
} else if (event.name === "down" || event.name === "j") {
|
|
548
|
-
|
|
553
|
+
move(1);
|
|
549
554
|
} else if (event.name === "return") {
|
|
550
|
-
const
|
|
551
|
-
if (
|
|
552
|
-
|
|
553
|
-
|
|
554
|
-
|
|
555
|
-
|
|
556
|
-
|
|
557
|
-
|
|
555
|
+
const onSubmitRow = hasSubmitRow && cursorRef.current === selectableItems.length;
|
|
556
|
+
if (onSubmitRow) {
|
|
557
|
+
dispatch({ type: "SUBMIT" });
|
|
558
|
+
onSubmit?.(Array.from(currentSelected));
|
|
559
|
+
} else {
|
|
560
|
+
const current = selectableItems[cursorRef.current];
|
|
561
|
+
if (current && !current.item.disabled) {
|
|
562
|
+
const isDeselecting = currentSelected.has(current.item.value);
|
|
563
|
+
if (!isDeselecting && maxCount !== void 0 && currentSelected.size >= maxCount) return;
|
|
564
|
+
const next = new Set(currentSelected);
|
|
565
|
+
if (isDeselecting) next.delete(current.item.value);
|
|
566
|
+
else next.add(current.item.value);
|
|
567
|
+
setSelected(Array.from(next));
|
|
568
|
+
}
|
|
558
569
|
}
|
|
559
570
|
} else if (event.name === "a" && enableSelectAll) {
|
|
560
571
|
const enabledValues = items.filter((i) => !i.disabled).map((i) => i.value);
|
|
561
572
|
setSelected(maxCount !== void 0 ? enabledValues.slice(0, maxCount) : enabledValues);
|
|
562
573
|
} else if (event.name === "x" && enableClear) {
|
|
563
574
|
setSelected([]);
|
|
564
|
-
} else if (event.name === "space" && currentSelected.size > 0) {
|
|
565
|
-
dispatch({ type: "SUBMIT" });
|
|
566
|
-
onSubmit?.(Array.from(currentSelected));
|
|
567
575
|
}
|
|
568
576
|
});
|
|
569
577
|
if (state.submitted) {
|
|
@@ -661,12 +669,17 @@ function MultiSelect({
|
|
|
661
669
|
/* @__PURE__ */ jsx10("span", { style: textStyle({ fg: itemColor, dim: isItemDisabled }), children: item.label })
|
|
662
670
|
] }, item.key ?? String(item.value));
|
|
663
671
|
}),
|
|
664
|
-
|
|
672
|
+
hasSubmitRow && /* @__PURE__ */ jsxs6("text", { children: [
|
|
665
673
|
/* @__PURE__ */ jsxs6("span", { style: textStyle({ fg: theme.muted }), children: [
|
|
666
674
|
BAR2,
|
|
667
675
|
" "
|
|
668
676
|
] }),
|
|
669
|
-
/* @__PURE__ */
|
|
677
|
+
/* @__PURE__ */ jsxs6("span", { style: textStyle({ fg: isOnSubmit ? resolvedHighlight : void 0 }), children: [
|
|
678
|
+
isOnSubmit ? CURSOR2 : " ",
|
|
679
|
+
" "
|
|
680
|
+
] }),
|
|
681
|
+
/* @__PURE__ */ jsx10("span", { style: textStyle({ fg: isOnSubmit ? resolvedHighlight : theme.muted }), children: "\u21B3 " }),
|
|
682
|
+
/* @__PURE__ */ jsx10("span", { style: textStyle({ fg: isOnSubmit ? resolvedHighlight : theme.text }), children: "Submit" })
|
|
670
683
|
] })
|
|
671
684
|
] });
|
|
672
685
|
}
|
|
@@ -1262,7 +1275,7 @@ function InstallBox() {
|
|
|
1262
1275
|
flexShrink: 0,
|
|
1263
1276
|
children: /* @__PURE__ */ jsxs14("text", { children: [
|
|
1264
1277
|
/* @__PURE__ */ jsx20("span", { style: textStyle({ dim: true }), children: "$ " }),
|
|
1265
|
-
/* @__PURE__ */ jsx20("span", { style: textStyle({ bold: true }), children: "
|
|
1278
|
+
/* @__PURE__ */ jsx20("span", { style: textStyle({ bold: true }), children: "bun create " }),
|
|
1266
1279
|
/* @__PURE__ */ jsx20("span", { style: textStyle({ fg: theme.accent }), children: "gridland" })
|
|
1267
1280
|
] })
|
|
1268
1281
|
}
|
|
@@ -1533,7 +1546,7 @@ function LandingApp({ useKeyboard: useKeyboard3 }) {
|
|
|
1533
1546
|
flexShrink: 0,
|
|
1534
1547
|
children: /* @__PURE__ */ jsxs17("text", { children: [
|
|
1535
1548
|
/* @__PURE__ */ jsx24("span", { style: textStyle({ dim: true }), children: "$ " }),
|
|
1536
|
-
/* @__PURE__ */ jsx24("span", { style: textStyle({ bold: true }), children: "
|
|
1549
|
+
/* @__PURE__ */ jsx24("span", { style: textStyle({ bold: true }), children: "bunx " }),
|
|
1537
1550
|
/* @__PURE__ */ jsx24("span", { style: textStyle({ fg: theme.accent }), children: "@gridland/demo landing" })
|
|
1538
1551
|
] })
|
|
1539
1552
|
}
|
|
@@ -1684,7 +1697,6 @@ function MultiSelectApp() {
|
|
|
1684
1697
|
{ key: "enter", label: "select" },
|
|
1685
1698
|
{ key: "a", label: "all" },
|
|
1686
1699
|
{ key: "x", label: "clear" },
|
|
1687
|
-
{ key: "space", label: "submit" },
|
|
1688
1700
|
{ key: "q", label: "quit" }
|
|
1689
1701
|
] })
|
|
1690
1702
|
] });
|