From 18668f4aea4bdd9ab672674c91a3729569315acc Mon Sep 17 00:00:00 2001 From: Hadi <112569860+anotherhadi@users.noreply.github.com> Date: Sun, 4 Oct 2026 18:46:49 +0200 Subject: [PATCH] fixes & update Signed-off-by: Hadi <112569860+anotherhadi@users.noreply.github.com> --- README.md | 9 +- dist/chunk-59dzyjgd.js | 25 +++ dist/{chunk-y6txxzxk.js => chunk-6ggk5fg7.js} | 10 +- dist/chunk-7f8jagy5.js | 22 --- dist/{chunk-ynqvwj4d.js => chunk-8r4rajaz.js} | 10 +- dist/{chunk-fqzxyvhv.js => chunk-ajb193xj.js} | 26 ++-- dist/{chunk-rvq53a2a.js => chunk-c1dx8cn3.js} | 12 +- dist/chunk-c4gp0x16.js | 44 ++++++ dist/chunk-cyvpvpws.js | 9 -- dist/chunk-ee2qaswx.js | 9 ++ dist/{chunk-xxg67vfz.js => chunk-ersd5rrs.js} | 29 ++-- dist/chunk-hcq62p48.js | 60 ------- dist/{chunk-2px9e43p.js => chunk-jza406qg.js} | 4 +- dist/chunk-kmqqzz9e.js | 35 +++++ dist/chunk-njvj322f.js | 65 ++++++++ dist/chunk-p6jvscj3.js | 79 ++++++++++ dist/{chunk-eta27h3c.js => chunk-qdyd8q9r.js} | 10 +- dist/{chunk-mezyz219.js => chunk-qhp6k176.js} | 22 +-- dist/{chunk-15vweq1q.js => chunk-rcywynbw.js} | 19 ++- dist/chunk-sh9n4zha.js | 71 +++++++++ dist/chunk-t2cszvff.js | 140 +++++++++++++++++ dist/{chunk-dctn29v0.js => chunk-tz3vvffs.js} | 10 +- dist/{chunk-bscbaa87.js => chunk-v9cetqzr.js} | 14 +- dist/chunk-vazj633p.js | 42 +++++ dist/{chunk-ev4wvhd2.js => chunk-vf2ybhtx.js} | 18 +-- dist/chunk-wtbg0e39.js | 52 +++++++ dist/chunk-x7m82z3z.js | 45 ------ dist/chunk-xykm10y9.js | 10 ++ dist/{chunk-cnhhssmz.js => chunk-yyg967q8.js} | 4 +- dist/{chunk-5m64a9kb.js => chunk-z734n0wr.js} | 12 +- dist/chunk-zjfxbvmq.js | 100 ------------ dist/components/Badge.js | 15 +- dist/components/Box.js | 15 +- dist/components/HelpBar.js | 15 +- dist/components/HelpModal.js | 19 +-- dist/components/KeyValue.js | 12 ++ dist/components/ListRow.js | 12 ++ dist/components/MinSizeGuard.js | 15 +- dist/components/Modal.js | 15 +- dist/components/NotificationHost.js | 16 +- dist/components/Pane.js | 10 ++ dist/components/ProgressBar.js | 15 +- dist/components/SectionHeader.js | 81 ++++++++++ dist/components/Sidebar.js | 15 +- dist/components/SignalBars.js | 15 +- dist/components/Spinner.js | 43 +----- dist/components/TabbedPanel.js | 14 ++ dist/components/Tabs.js | 19 +-- dist/components/Toggle.js | 17 +- dist/components/help.js | 25 +-- dist/components/index.js | 93 ++++++----- dist/config.js | 26 ++-- dist/context/focus.js | 9 ++ dist/context/help.js | 10 +- dist/context/helper.js | 6 +- dist/context/index.js | 36 +++-- dist/context/notifications.js | 14 +- dist/index.js | 28 ++-- dist/keymap/provider.js | 8 +- dist/presets.js | 6 +- dist/project-config.js | 52 ++++++- dist/solid.js | 35 +++-- dist/yaml.js | 8 +- package.json | 3 +- src/components/HelpModal.tsx | 14 +- src/components/KeyValue.tsx | 23 +++ src/components/ListRow.tsx | 49 ++++++ src/components/Modal.tsx | 146 ++++++++++++------ src/components/Pane.tsx | 48 ++++++ src/components/SectionHeader.tsx | 40 +++++ src/components/Sidebar.tsx | 10 +- src/components/TabbedPanel.tsx | 28 ++++ src/components/index.ts | 6 +- src/config.ts | 118 ++++++-------- src/context/focus.ts | 30 ++++ src/context/index.ts | 1 + src/index.ts | 86 ++++++++--- src/project-config.ts | 60 +++++++ src/solid.ts | 26 ++-- src/yaml.ts | 12 -- 80 files changed, 1682 insertions(+), 754 deletions(-) create mode 100644 dist/chunk-59dzyjgd.js rename dist/{chunk-y6txxzxk.js => chunk-6ggk5fg7.js} (69%) delete mode 100644 dist/chunk-7f8jagy5.js rename dist/{chunk-ynqvwj4d.js => chunk-8r4rajaz.js} (76%) rename dist/{chunk-fqzxyvhv.js => chunk-ajb193xj.js} (81%) rename dist/{chunk-rvq53a2a.js => chunk-c1dx8cn3.js} (95%) create mode 100644 dist/chunk-c4gp0x16.js delete mode 100644 dist/chunk-cyvpvpws.js create mode 100644 dist/chunk-ee2qaswx.js rename dist/{chunk-xxg67vfz.js => chunk-ersd5rrs.js} (80%) delete mode 100644 dist/chunk-hcq62p48.js rename dist/{chunk-2px9e43p.js => chunk-jza406qg.js} (89%) create mode 100644 dist/chunk-kmqqzz9e.js create mode 100644 dist/chunk-njvj322f.js create mode 100644 dist/chunk-p6jvscj3.js rename dist/{chunk-eta27h3c.js => chunk-qdyd8q9r.js} (91%) rename dist/{chunk-mezyz219.js => chunk-qhp6k176.js} (77%) rename dist/{chunk-15vweq1q.js => chunk-rcywynbw.js} (81%) create mode 100644 dist/chunk-sh9n4zha.js create mode 100644 dist/chunk-t2cszvff.js rename dist/{chunk-dctn29v0.js => chunk-tz3vvffs.js} (85%) rename dist/{chunk-bscbaa87.js => chunk-v9cetqzr.js} (90%) create mode 100644 dist/chunk-vazj633p.js rename dist/{chunk-ev4wvhd2.js => chunk-vf2ybhtx.js} (93%) create mode 100644 dist/chunk-wtbg0e39.js delete mode 100644 dist/chunk-x7m82z3z.js create mode 100644 dist/chunk-xykm10y9.js rename dist/{chunk-cnhhssmz.js => chunk-yyg967q8.js} (95%) rename dist/{chunk-5m64a9kb.js => chunk-z734n0wr.js} (90%) delete mode 100644 dist/chunk-zjfxbvmq.js create mode 100644 dist/components/KeyValue.js create mode 100644 dist/components/ListRow.js create mode 100644 dist/components/Pane.js create mode 100644 dist/components/SectionHeader.js create mode 100644 dist/components/TabbedPanel.js create mode 100644 dist/context/focus.js create mode 100644 src/components/KeyValue.tsx create mode 100644 src/components/ListRow.tsx create mode 100644 src/components/Pane.tsx create mode 100644 src/components/SectionHeader.tsx create mode 100644 src/components/TabbedPanel.tsx create mode 100644 src/context/focus.ts diff --git a/README.md b/README.md index 6dd79cd..ebf3457 100644 --- a/README.md +++ b/README.md @@ -17,6 +17,13 @@ import { theme, presets } from "ilovetui"; import "ilovetui/solid"; ``` -Entry points: `.`, `./solid`, `./context`, `./project-config`, `./keymap`, `./components`, `./components/help`, `./components/spinner`. See the source for what each exports. +Entry points: `.`, `./solid`, `./context`, `./project-config`, `./keymap`, `./components`, `./components/help`, `./components/spinner`, `./components/section-header`. See the source for what each exports. The theme is base16 and user-overridable via `~/.config/ilovetui/config.yaml`. Copy [`src/default.yaml`](https://github.com/anotherhadi/ilovetui/blob/main/src/default.yaml) there as a starting point. + +An app can layer its own theme overrides on top of that file (e.g. a `theme:` section of its own config, validated with `ThemeConfigSchema`) by calling `configureTheme(overrides)` once at startup, before the first render. Invalid theme files are reported as warning toasts and skipped; unknown keys are ignored, so other TUIs can keep their own keys in the shared file. + +## Focus and keymap scoping + +Wrap each focus region in a `` (`focusable` when the pane itself is the focus target). Inside it, `usePane()` gives `target` — pass it to `useBindings` so the layer is only active while focus is within the pane — and `focused()` for styling. `` takes focus while open, restores it on close, and binds its `dismissKey` (default `escape`) plus any `commands`/`bindings` you pass, scoped to itself. Note that keymap layers are ordered by `priority` then registration order, not by tree depth: keep overlapping layers on disjoint targets, or give them explicit priorities. + diff --git a/dist/chunk-59dzyjgd.js b/dist/chunk-59dzyjgd.js new file mode 100644 index 0000000..013d456 --- /dev/null +++ b/dist/chunk-59dzyjgd.js @@ -0,0 +1,25 @@ +// @bun +// src/context/focus.ts +import { CliRenderEvents } from "@opentui/core"; +import { useRenderer } from "@opentui/solid"; +import { createEffect, createSignal, onCleanup } from "solid-js"; +function isInside2(node, root) { + if (!root) + return false; + for (let current = node;current; current = current.parent) { + if (current === root) + return true; + } + return false; +} +function useFocusWithin2(target) { + const renderer = useRenderer(); + const [focused, setFocused] = createSignal(false); + const sync = () => setFocused(isInside2(renderer.currentFocusedRenderable, target() ?? null)); + renderer.on(CliRenderEvents.FOCUSED_RENDERABLE, sync); + onCleanup(() => renderer.off(CliRenderEvents.FOCUSED_RENDERABLE, sync)); + createEffect(sync); + return focused; +} + +export { isInside2, useFocusWithin2 }; diff --git a/dist/chunk-y6txxzxk.js b/dist/chunk-6ggk5fg7.js similarity index 69% rename from dist/chunk-y6txxzxk.js rename to dist/chunk-6ggk5fg7.js index c5fdb1d..6fe868b 100644 --- a/dist/chunk-y6txxzxk.js +++ b/dist/chunk-6ggk5fg7.js @@ -2,20 +2,20 @@ // src/context/notifications.ts import { createSignal } from "solid-js"; var DEFAULT_DURATION = 3000; -var [notifications, setNotifications] = createSignal([]); +var [notifications2, setNotifications] = createSignal([]); var nextId = 0; -function notify(message, options = {}) { +function notify2(message, options = {}) { const id = options.id ?? `toast-${nextId++}`; const toast = { id, title: options.title, message, kind: options.kind ?? "info" }; setNotifications((prev) => [...prev.filter((n) => n.id !== id), toast]); const duration = options.duration ?? DEFAULT_DURATION; if (duration > 0) { - setTimeout(() => dismiss(id), duration); + setTimeout(() => dismiss2(id), duration); } return id; } -function dismiss(id) { +function dismiss2(id) { setNotifications((prev) => prev.filter((n) => n.id !== id)); } -export { notifications, notify, dismiss }; +export { notifications2, notify2, dismiss2 }; diff --git a/dist/chunk-7f8jagy5.js b/dist/chunk-7f8jagy5.js deleted file mode 100644 index 094e75d..0000000 --- a/dist/chunk-7f8jagy5.js +++ /dev/null @@ -1,22 +0,0 @@ -// @bun -// src/yaml.ts -import { existsSync, readFileSync } from "fs"; -import { homedir } from "os"; -import { join } from "path"; -import { parse as parseYAML } from "yaml"; -function configPath() { - const configDir = process.env.XDG_CONFIG_HOME || join(homedir(), ".config"); - return join(configDir, "ilovetui", "config.yaml"); -} -function readYamlFile(path) { - if (!existsSync(path)) - return; - try { - return parseYAML(readFileSync(path, "utf8")) ?? undefined; - } catch (err) { - console.error(`ilovetui: failed to parse ${path}, ignoring it.`, err); - return; - } -} - -export { configPath, readYamlFile }; diff --git a/dist/chunk-ynqvwj4d.js b/dist/chunk-8r4rajaz.js similarity index 76% rename from dist/chunk-ynqvwj4d.js rename to dist/chunk-8r4rajaz.js index 833fef0..39d361d 100644 --- a/dist/chunk-ynqvwj4d.js +++ b/dist/chunk-8r4rajaz.js @@ -1,23 +1,23 @@ // @bun import { - theme -} from "./chunk-x7m82z3z.js"; + theme2 +} from "./chunk-p6jvscj3.js"; // src/components/Box.tsx import { spread as _$spread } from "@opentui/solid"; import { mergeProps as _$mergeProps } from "@opentui/solid"; import { memo as _$memo } from "@opentui/solid"; import { createElement as _$createElement } from "@opentui/solid"; -function Box(props) { +function Box2(props) { return (() => { var _el$ = _$createElement("box"); _$spread(_el$, _$mergeProps(props, { get borderStyle() { - return props.borderStyle ?? theme.borderStyle; + return props.borderStyle ?? theme2.borderStyle; } }), false); return _el$; })(); } -export { Box }; +export { Box2 }; diff --git a/dist/chunk-fqzxyvhv.js b/dist/chunk-ajb193xj.js similarity index 81% rename from dist/chunk-fqzxyvhv.js rename to dist/chunk-ajb193xj.js index 5a8d359..199a358 100644 --- a/dist/chunk-fqzxyvhv.js +++ b/dist/chunk-ajb193xj.js @@ -1,11 +1,11 @@ // @bun import { - theme -} from "./chunk-x7m82z3z.js"; + notifications2, + dismiss2 +} from "./chunk-6ggk5fg7.js"; import { - dismiss, - notifications -} from "./chunk-y6txxzxk.js"; + theme2 +} from "./chunk-p6jvscj3.js"; // src/components/NotificationHost.tsx import { effect as _$effect } from "@opentui/solid"; @@ -23,12 +23,12 @@ var KIND_LABEL = { warning: "Warning", error: "Error" }; -function NotificationHost(props = {}) { +function NotificationHost2(props = {}) { const defaultColor = () => ({ - info: theme.primary, - success: theme.success, - warning: theme.warning, - error: theme.error + info: theme2.primary, + success: theme2.success, + warning: theme2.warning, + error: theme2.error }); const colorFor = (kind) => props.colors?.[kind] ?? defaultColor()[kind]; return _$createComponent(Portal, { @@ -41,7 +41,7 @@ function NotificationHost(props = {}) { _$setProp(_el$, "zIndex", 1000); _$insert(_el$, _$createComponent(For, { get each() { - return notifications(); + return notifications2(); }, children: (toast) => (() => { var _el$2 = _$createElement("box"), _el$3 = _$createElement("text"), _el$4 = _$createElement("text"); @@ -52,7 +52,7 @@ function NotificationHost(props = {}) { _$insert(_el$3, () => toast.title ?? KIND_LABEL[toast.kind]); _$insert(_el$4, () => toast.message); _$effect((_p$) => { - var _v$ = theme.borderStyle, _v$2 = colorFor(toast.kind), _v$3 = props.backgroundColor ?? theme.background, _v$4 = props.width ?? 32, _v$5 = theme.mouse ? () => dismiss(toast.id) : undefined, _v$6 = colorFor(toast.kind); + var _v$ = theme2.borderStyle, _v$2 = colorFor(toast.kind), _v$3 = props.backgroundColor ?? theme2.background, _v$4 = props.width ?? 32, _v$5 = theme2.mouse ? () => dismiss2(toast.id) : undefined, _v$6 = colorFor(toast.kind); _v$ !== _p$.e && (_p$.e = _$setProp(_el$2, "borderStyle", _v$, _p$.e)); _v$2 !== _p$.t && (_p$.t = _$setProp(_el$2, "borderColor", _v$2, _p$.t)); _v$3 !== _p$.a && (_p$.a = _$setProp(_el$2, "backgroundColor", _v$3, _p$.a)); @@ -76,4 +76,4 @@ function NotificationHost(props = {}) { }); } -export { NotificationHost }; +export { NotificationHost2 }; diff --git a/dist/chunk-rvq53a2a.js b/dist/chunk-c1dx8cn3.js similarity index 95% rename from dist/chunk-rvq53a2a.js rename to dist/chunk-c1dx8cn3.js index 3883e9d..8a8302e 100644 --- a/dist/chunk-rvq53a2a.js +++ b/dist/chunk-c1dx8cn3.js @@ -1,7 +1,7 @@ // @bun import { - theme -} from "./chunk-x7m82z3z.js"; + theme2 +} from "./chunk-p6jvscj3.js"; // src/components/HelpBar.tsx import { createTextNode as _$createTextNode } from "@opentui/solid"; @@ -28,9 +28,9 @@ var KEY_DISPLAY = { }; var SEPARATOR = " "; var ELLIPSIS = "\u2026"; -function HelpBar(props = {}) { - const accent = () => props.accentColor ?? theme.primary; - const muted = () => props.mutedColor ?? theme.muted; +function HelpBar2(props = {}) { + const accent = () => props.accentColor ?? theme2.primary; + const muted = () => props.mutedColor ?? theme2.muted; const renderer = useRenderer(); const [width, setWidth] = createSignal(0); let container; @@ -118,4 +118,4 @@ function HelpBar(props = {}) { })(); } -export { HelpBar }; +export { HelpBar2 }; diff --git a/dist/chunk-c4gp0x16.js b/dist/chunk-c4gp0x16.js new file mode 100644 index 0000000..254efe9 --- /dev/null +++ b/dist/chunk-c4gp0x16.js @@ -0,0 +1,44 @@ +// @bun +import { + theme2 +} from "./chunk-p6jvscj3.js"; + +// src/components/KeyValue.tsx +import { memo as _$memo } from "@opentui/solid"; +import { effect as _$effect } from "@opentui/solid"; +import { insertNode as _$insertNode } from "@opentui/solid"; +import { createComponent as _$createComponent } from "@opentui/solid"; +import { insert as _$insert } from "@opentui/solid"; +import { setProp as _$setProp } from "@opentui/solid"; +import { createElement as _$createElement } from "@opentui/solid"; +import { Show } from "solid-js"; +function KeyValue2(props) { + return (() => { + var _el$ = _$createElement("box"), _el$2 = _$createElement("text"); + _$insertNode(_el$, _el$2); + _$setProp(_el$, "flexShrink", 0); + _$setProp(_el$, "flexDirection", "row"); + _$setProp(_el$, "justifyContent", "space-between"); + _$insert(_el$2, () => props.label); + _$insert(_el$, _$createComponent(Show, { + get when() { + return props.children; + }, + get fallback() { + return (() => { + var _el$3 = _$createElement("text"); + _$insert(_el$3, () => props.value ?? ""); + _$effect((_$p) => _$setProp(_el$3, "fg", props.valueColor, _$p)); + return _el$3; + })(); + }, + get children() { + return props.children; + } + }), null); + _$effect((_$p) => _$setProp(_el$2, "fg", theme2.muted, _$p)); + return _el$; + })(); +} + +export { KeyValue2 }; diff --git a/dist/chunk-cyvpvpws.js b/dist/chunk-cyvpvpws.js deleted file mode 100644 index 25a10f1..0000000 --- a/dist/chunk-cyvpvpws.js +++ /dev/null @@ -1,9 +0,0 @@ -// @bun -// src/context/help.ts -import { createSignal } from "solid-js"; -var [helpOpen, setHelpOpen] = createSignal(false); -function toggleHelp() { - setHelpOpen((open) => !open); -} - -export { helpOpen, toggleHelp }; diff --git a/dist/chunk-ee2qaswx.js b/dist/chunk-ee2qaswx.js new file mode 100644 index 0000000..1e6ee6e --- /dev/null +++ b/dist/chunk-ee2qaswx.js @@ -0,0 +1,9 @@ +// @bun +// src/context/help.ts +import { createSignal } from "solid-js"; +var [helpOpen2, setHelpOpen] = createSignal(false); +function toggleHelp2() { + setHelpOpen((open) => !open); +} + +export { helpOpen2, toggleHelp2 }; diff --git a/dist/chunk-xxg67vfz.js b/dist/chunk-ersd5rrs.js similarity index 80% rename from dist/chunk-xxg67vfz.js rename to dist/chunk-ersd5rrs.js index 73f209d..62f27ec 100644 --- a/dist/chunk-xxg67vfz.js +++ b/dist/chunk-ersd5rrs.js @@ -1,11 +1,11 @@ // @bun import { - Modal -} from "./chunk-zjfxbvmq.js"; + helpOpen2, + toggleHelp2 +} from "./chunk-ee2qaswx.js"; import { - helpOpen, - toggleHelp -} from "./chunk-cyvpvpws.js"; + Modal2 +} from "./chunk-t2cszvff.js"; // src/components/HelpModal.tsx import { createComponent as _$createComponent } from "@opentui/solid"; @@ -18,6 +18,7 @@ import { createElement as _$createElement } from "@opentui/solid"; import { TextAttributes } from "@opentui/core"; import { formatCommandBindings } from "@opentui/keymap/extras"; import { useKeymapSelector } from "@opentui/keymap/solid"; +import { createSignal } from "solid-js"; var KEY_DISPLAY = { up: "\u2191", down: "\u2193", @@ -26,9 +27,11 @@ var KEY_DISPLAY = { enter: "Enter", escape: "Esc" }; -function HelpModal(props = {}) { +function HelpModal2(props = {}) { + const [scope, setScope] = createSignal(null); const entries = useKeymapSelector((keymap) => keymap.getCommandEntries({ - visibility: "active" + visibility: "active", + focused: scope() }).map((entry) => ({ command: entry.command.name, keys: formatCommandBindings(entry.bindings, { @@ -36,11 +39,15 @@ function HelpModal(props = {}) { }) ?? "", label: typeof entry.command.desc === "string" ? entry.command.desc : entry.command.name }))); - return _$createComponent(Modal, { + return _$createComponent(Modal2, { get open() { - return helpOpen(); + return helpOpen2(); + }, + onDismiss: toggleHelp2, + onOpen: (previous) => setScope(() => previous), + get dismissKey() { + return props.dismissKey; }, - onDismiss: toggleHelp, get accentColor() { return props.accentColor; }, @@ -77,4 +84,4 @@ function HelpModal(props = {}) { }); } -export { HelpModal }; +export { HelpModal2 }; diff --git a/dist/chunk-hcq62p48.js b/dist/chunk-hcq62p48.js deleted file mode 100644 index c5a9fbc..0000000 --- a/dist/chunk-hcq62p48.js +++ /dev/null @@ -1,60 +0,0 @@ -// @bun -// src/config.ts -var COLOR_KEYS = [ - "base00", - "base01", - "base02", - "base03", - "base04", - "base05", - "base06", - "base07", - "base08", - "base09", - "base0a", - "base0b", - "base0c", - "base0d", - "base0e", - "base0f" -]; -function mergeColors(base, user) { - const merged = {}; - for (const key of COLOR_KEYS) { - merged[key] = user[key] || base[key] || ""; - } - return merged; -} -function mergeConfig(base, user) { - return { - nerdFonts: user.nerd_fonts ?? base.nerd_fonts ?? false, - emojiFonts: user.emoji_fonts ?? base.emoji_fonts ?? false, - reducedMotion: user.reduced_motion ?? base.reduced_motion ?? false, - mouse: user.mouse ?? base.mouse ?? true, - border: user.border || base.border || "rounded", - colors: mergeColors(base.colors ?? {}, user.colors ?? {}) - }; -} -function normalizeColor(hex) { - const trimmed = hex.trim(); - if (trimmed && !trimmed.startsWith("#")) - return `#${trimmed}`; - return trimmed; -} -function normalizeColors(colors) { - const out = {}; - for (const key of COLOR_KEYS) - out[key] = normalizeColor(colors[key]); - return out; -} -var OPENTUI_BORDER_STYLES = [ - "single", - "double", - "rounded", - "heavy" -]; -function resolveBorderStyle(name) { - return OPENTUI_BORDER_STYLES.includes(name) ? name : "rounded"; -} - -export { COLOR_KEYS, mergeColors, mergeConfig, normalizeColor, normalizeColors, resolveBorderStyle }; diff --git a/dist/chunk-2px9e43p.js b/dist/chunk-jza406qg.js similarity index 89% rename from dist/chunk-2px9e43p.js rename to dist/chunk-jza406qg.js index abd798f..aed3faf 100644 --- a/dist/chunk-2px9e43p.js +++ b/dist/chunk-jza406qg.js @@ -2,7 +2,7 @@ // src/context/helper.tsx import { createComponent as _$createComponent } from "@opentui/solid"; import { createContext, useContext } from "solid-js"; -function createSimpleContext(input) { +function createSimpleContext2(input) { const ctx = createContext(); return { provider: (props) => { @@ -23,4 +23,4 @@ function createSimpleContext(input) { }; } -export { createSimpleContext }; +export { createSimpleContext2 }; diff --git a/dist/chunk-kmqqzz9e.js b/dist/chunk-kmqqzz9e.js new file mode 100644 index 0000000..99ef023 --- /dev/null +++ b/dist/chunk-kmqqzz9e.js @@ -0,0 +1,35 @@ +// @bun +import { + theme2 +} from "./chunk-p6jvscj3.js"; + +// src/components/Spinner.tsx +import { setProp as _$setProp } from "@opentui/solid"; +import { effect as _$effect } from "@opentui/solid"; +import { createElement as _$createElement } from "@opentui/solid"; +import"opentui-spinner/solid"; +function Spinner2(props) { + return (() => { + var _el$ = _$createElement("spinner"); + _$effect((_p$) => { + var { name: _v$, frames: _v$2, interval: _v$3 } = props, _v$4 = props.autoplay ?? !theme2.reducedMotion, _v$5 = props.color ?? theme2.primary, _v$6 = props.backgroundColor; + _v$ !== _p$.e && (_p$.e = _$setProp(_el$, "name", _v$, _p$.e)); + _v$2 !== _p$.t && (_p$.t = _$setProp(_el$, "frames", _v$2, _p$.t)); + _v$3 !== _p$.a && (_p$.a = _$setProp(_el$, "interval", _v$3, _p$.a)); + _v$4 !== _p$.o && (_p$.o = _$setProp(_el$, "autoplay", _v$4, _p$.o)); + _v$5 !== _p$.i && (_p$.i = _$setProp(_el$, "color", _v$5, _p$.i)); + _v$6 !== _p$.n && (_p$.n = _$setProp(_el$, "backgroundColor", _v$6, _p$.n)); + return _p$; + }, { + e: undefined, + t: undefined, + a: undefined, + o: undefined, + i: undefined, + n: undefined + }); + return _el$; + })(); +} + +export { Spinner2 }; diff --git a/dist/chunk-njvj322f.js b/dist/chunk-njvj322f.js new file mode 100644 index 0000000..15c1a4d --- /dev/null +++ b/dist/chunk-njvj322f.js @@ -0,0 +1,65 @@ +// @bun +// src/config.ts +import { z } from "zod"; +var COLOR_KEYS2 = [ + "base00", + "base01", + "base02", + "base03", + "base04", + "base05", + "base06", + "base07", + "base08", + "base09", + "base0a", + "base0b", + "base0c", + "base0d", + "base0e", + "base0f" +]; +var OPENTUI_BORDER_STYLES2 = ["single", "double", "rounded", "heavy"]; +var hexColor = z.string().regex(/^#?[0-9a-fA-F]{6}$/, 'expected a hex color like "#1e1e2e"'); +var colorsShape = {}; +for (const key of COLOR_KEYS2) + colorsShape[key] = hexColor.optional(); +var ThemeConfigSchema2 = z.object({ + nerd_fonts: z.boolean().optional(), + emoji_fonts: z.boolean().optional(), + reduced_motion: z.boolean().optional(), + mouse: z.boolean().optional(), + border: z.enum(OPENTUI_BORDER_STYLES2).optional(), + colors: z.object(colorsShape).optional() +}); +function layerConfigs2(layers) { + const out = {}; + for (const layer of layers) { + const { colors, ...rest } = layer; + Object.assign(out, rest); + if (colors) + out.colors = { ...out.colors, ...colors }; + } + return out; +} +function resolveConfig2(config) { + const colors = {}; + for (const key of COLOR_KEYS2) + colors[key] = normalizeColor2(config.colors?.[key] ?? ""); + return { + nerdFonts: config.nerd_fonts ?? false, + emojiFonts: config.emoji_fonts ?? false, + reducedMotion: config.reduced_motion ?? false, + mouse: config.mouse ?? true, + border: config.border ?? "rounded", + colors + }; +} +function normalizeColor2(hex) { + const trimmed = hex.trim(); + if (trimmed && !trimmed.startsWith("#")) + return `#${trimmed}`; + return trimmed; +} + +export { COLOR_KEYS2, OPENTUI_BORDER_STYLES2, ThemeConfigSchema2, layerConfigs2, resolveConfig2, normalizeColor2 }; diff --git a/dist/chunk-p6jvscj3.js b/dist/chunk-p6jvscj3.js new file mode 100644 index 0000000..c2767e4 --- /dev/null +++ b/dist/chunk-p6jvscj3.js @@ -0,0 +1,79 @@ +// @bun +import { + ThemeConfigSchema2, + layerConfigs2, + resolveConfig2 +} from "./chunk-njvj322f.js"; +import { + notify2 +} from "./chunk-6ggk5fg7.js"; +import { + buildPresets2 +} from "./chunk-yyg967q8.js"; +import { + configPath2 +} from "./chunk-xykm10y9.js"; + +// src/index.ts +import { existsSync, readFileSync } from "fs"; +import { join } from "path"; +import { parse as parseYAML } from "yaml"; +import { z } from "zod"; +function reportThemeError(path, message) { + const text = `${path}: ${message}`; + console.error(`[ilovetui theme] ${text}`); + notify2(text, { kind: "warning", duration: 0 }); +} +function readThemeFile(path) { + if (!existsSync(path)) + return {}; + let raw; + try { + raw = parseYAML(readFileSync(path, "utf8")); + } catch (error) { + reportThemeError(path, error instanceof Error ? error.message : String(error)); + return {}; + } + const result = ThemeConfigSchema2.safeParse(raw ?? {}); + if (!result.success) { + reportThemeError(path, z.prettifyError(result.error)); + return {}; + } + return result.data; +} +var fileLayers = [readThemeFile(join(import.meta.dir, "default.yaml")), readThemeFile(configPath2())]; +function buildTheme(overrides) { + const resolved = resolveConfig2(layerConfigs2([...fileLayers, overrides])); + const colors = resolved.colors; + return { + ...colors, + background: colors.base00, + subtleBg: colors.base01, + selection: colors.base02, + subtle: colors.base03, + muted: colors.base04, + text: colors.base05, + primary: colors.base0d, + success: colors.base0b, + warning: colors.base09, + error: colors.base08, + nerdFonts: resolved.nerdFonts, + emojiFonts: resolved.emojiFonts, + reducedMotion: resolved.reducedMotion, + mouse: resolved.mouse, + borderStyle: resolved.border + }; +} +var theme2 = buildTheme({}); +var presets2 = buildPresets2(theme2); +function configureTheme2(overrides = {}) { + Object.assign(theme2, buildTheme(overrides)); + const next = buildPresets2(theme2); + for (const key of Object.keys(next)) + Object.assign(presets2[key], next[key]); +} +function icon2(codepoint) { + return theme2.nerdFonts ? `${codepoint} ` : ""; +} + +export { theme2, presets2, configureTheme2, icon2 }; diff --git a/dist/chunk-eta27h3c.js b/dist/chunk-qdyd8q9r.js similarity index 91% rename from dist/chunk-eta27h3c.js rename to dist/chunk-qdyd8q9r.js index daee13f..7644347 100644 --- a/dist/chunk-eta27h3c.js +++ b/dist/chunk-qdyd8q9r.js @@ -1,7 +1,7 @@ // @bun import { - theme -} from "./chunk-x7m82z3z.js"; + theme2 +} from "./chunk-p6jvscj3.js"; // src/components/MinSizeGuard.tsx import { createComponent as _$createComponent } from "@opentui/solid"; @@ -13,7 +13,7 @@ import { createElement as _$createElement } from "@opentui/solid"; import { memo as _$memo } from "@opentui/solid"; import { useTerminalDimensions } from "@opentui/solid"; import { Show } from "solid-js"; -function MinSizeGuard(props) { +function MinSizeGuard2(props) { const dimensions = useTerminalDimensions(); const minWidth = () => props.minWidth ?? 80; const minHeight = () => props.minHeight ?? 24; @@ -34,7 +34,7 @@ function MinSizeGuard(props) { _$insert(_el$2, () => `Terminal too small Minimum size: ${minWidth()}x${minHeight()} \u2014 current: ${dimensions().width}x${dimensions().height}`); _$effect((_p$) => { - var _v$ = dimensions().width, _v$2 = dimensions().height, _v$3 = props.backgroundColor ?? theme.background, _v$4 = props.textColor ?? theme.muted; + var _v$ = dimensions().width, _v$2 = dimensions().height, _v$3 = props.backgroundColor ?? theme2.background, _v$4 = props.textColor ?? theme2.muted; _v$ !== _p$.e && (_p$.e = _$setProp(_el$, "width", _v$, _p$.e)); _v$2 !== _p$.t && (_p$.t = _$setProp(_el$, "height", _v$2, _p$.t)); _v$3 !== _p$.a && (_p$.a = _$setProp(_el$, "backgroundColor", _v$3, _p$.a)); @@ -51,4 +51,4 @@ Minimum size: ${minWidth()}x${minHeight()} \u2014 current: ${dimensions().width} })]; } -export { MinSizeGuard }; +export { MinSizeGuard2 }; diff --git a/dist/chunk-mezyz219.js b/dist/chunk-qhp6k176.js similarity index 77% rename from dist/chunk-mezyz219.js rename to dist/chunk-qhp6k176.js index 1fdf90d..0a84298 100644 --- a/dist/chunk-mezyz219.js +++ b/dist/chunk-qhp6k176.js @@ -1,10 +1,10 @@ // @bun import { - Badge -} from "./chunk-bscbaa87.js"; + theme2 +} from "./chunk-p6jvscj3.js"; import { - theme -} from "./chunk-x7m82z3z.js"; + Badge2 +} from "./chunk-v9cetqzr.js"; // src/components/Toggle.tsx import { setProp as _$setProp } from "@opentui/solid"; @@ -15,10 +15,10 @@ import { memo as _$memo } from "@opentui/solid"; import { createElement as _$createElement } from "@opentui/solid"; import { TextAttributes } from "@opentui/core"; import { Show } from "solid-js"; -function Toggle(props) { - const onColor = () => props.onColor ?? theme.success; - const offColor = () => props.offColor ?? theme.muted; - const nerdFonts = () => props.withNerdfont ?? theme.nerdFonts; +function Toggle2(props) { + const onColor = () => props.onColor ?? theme2.success; + const offColor = () => props.offColor ?? theme2.muted; + const nerdFonts = () => props.withNerdfont ?? theme2.nerdFonts; return (() => { var _el$ = _$createElement("box"); _$insert(_el$, _$createComponent(Show, { @@ -42,7 +42,7 @@ function Toggle(props) { })(); }, get children() { - return _$createComponent(Badge, { + return _$createComponent(Badge2, { get label() { return props.on ? " \u25CF" : "\u25CF "; }, @@ -53,9 +53,9 @@ function Toggle(props) { }); } })); - _$effect((_$p) => _$setProp(_el$, "onMouseDown", theme.mouse ? props.onToggle : undefined, _$p)); + _$effect((_$p) => _$setProp(_el$, "onMouseDown", theme2.mouse ? props.onToggle : undefined, _$p)); return _el$; })(); } -export { Toggle }; +export { Toggle2 }; diff --git a/dist/chunk-15vweq1q.js b/dist/chunk-rcywynbw.js similarity index 81% rename from dist/chunk-15vweq1q.js rename to dist/chunk-rcywynbw.js index 026d649..3270c36 100644 --- a/dist/chunk-15vweq1q.js +++ b/dist/chunk-rcywynbw.js @@ -1,8 +1,8 @@ // @bun import { - presets, - theme -} from "./chunk-x7m82z3z.js"; + theme2, + presets2 +} from "./chunk-p6jvscj3.js"; // src/components/Sidebar.tsx import { use as _$use } from "@opentui/solid"; @@ -14,7 +14,7 @@ import { insert as _$insert } from "@opentui/solid"; import { setProp as _$setProp } from "@opentui/solid"; import { createElement as _$createElement } from "@opentui/solid"; import { TextAttributes } from "@opentui/core"; -import { Show } from "solid-js"; +import { createEffect, Show } from "solid-js"; function truncateWithEllipsis(text, maxWidth) { if (maxWidth <= 0) return ""; @@ -35,7 +35,7 @@ function itemIndexAtScreenY(el, screenY) { var BORDER_WIDTH = 2; var ITEM_LEFT_PADDING = 1; var ITEM_INDICATOR_WIDTH = 2; -function Sidebar(props) { +function Sidebar2(props) { let select; const contentWidth = () => Math.max(0, (props.width ?? 24) - BORDER_WIDTH); const itemTextWidth = () => Math.max(0, contentWidth() - ITEM_LEFT_PADDING - ITEM_INDICATOR_WIDTH); @@ -65,6 +65,11 @@ function Sidebar(props) { else if (event.scroll.direction === "up") select.moveUp(steps); }; + createEffect(() => { + const index = props.items.findIndex((item) => item.value === props.value); + if (select && index !== -1 && select.getSelectedIndex() !== index) + select.setSelectedIndex(index); + }); return (() => { var _el$ = _$createElement("box"), _el$5 = _$createElement("select"); _$insertNode(_el$, _el$5); @@ -109,7 +114,7 @@ function Sidebar(props) { props.onConfirm?.(option); }); _$effect((_p$) => { - var _v$ = props.width ?? 24, _v$2 = theme.borderStyle, _v$3 = props.focused ? props.accentColor ?? theme.primary : props.mutedColor ?? theme.muted, _v$4 = props.focused, _v$5 = displayItems(), _v$6 = theme.mouse ? handleMouseDown : undefined, _v$7 = theme.mouse ? handleMouseScroll : undefined, _v$8 = props.backgroundColor ?? "transparent", _v$9 = props.textColor ?? presets.select.textColor, _v$0 = props.focusedBackgroundColor ?? "transparent", _v$1 = props.focusedTextColor ?? presets.select.focusedTextColor, _v$10 = props.selectedBackgroundColor ?? presets.select.selectedBackgroundColor, _v$11 = props.selectedTextColor ?? presets.select.selectedTextColor, _v$12 = props.descriptionColor ?? presets.select.descriptionColor, _v$13 = props.selectedDescriptionColor ?? presets.select.selectedDescriptionColor; + var _v$ = props.width ?? 24, _v$2 = theme2.borderStyle, _v$3 = props.focused ? props.accentColor ?? theme2.primary : props.mutedColor ?? theme2.muted, _v$4 = props.focused, _v$5 = displayItems(), _v$6 = theme2.mouse ? handleMouseDown : undefined, _v$7 = theme2.mouse ? handleMouseScroll : undefined, _v$8 = props.backgroundColor ?? "transparent", _v$9 = props.textColor ?? presets2.select.textColor, _v$0 = props.focusedBackgroundColor ?? "transparent", _v$1 = props.focusedTextColor ?? presets2.select.focusedTextColor, _v$10 = props.selectedBackgroundColor ?? presets2.select.selectedBackgroundColor, _v$11 = props.selectedTextColor ?? presets2.select.selectedTextColor, _v$12 = props.descriptionColor ?? presets2.select.descriptionColor, _v$13 = props.selectedDescriptionColor ?? presets2.select.selectedDescriptionColor; _v$ !== _p$.e && (_p$.e = _$setProp(_el$, "width", _v$, _p$.e)); _v$2 !== _p$.t && (_p$.t = _$setProp(_el$, "borderStyle", _v$2, _p$.t)); _v$3 !== _p$.a && (_p$.a = _$setProp(_el$, "borderColor", _v$3, _p$.a)); @@ -147,4 +152,4 @@ function Sidebar(props) { })(); } -export { Sidebar }; +export { Sidebar2 }; diff --git a/dist/chunk-sh9n4zha.js b/dist/chunk-sh9n4zha.js new file mode 100644 index 0000000..cbb80a8 --- /dev/null +++ b/dist/chunk-sh9n4zha.js @@ -0,0 +1,71 @@ +// @bun +import { + theme2, + presets2 +} from "./chunk-p6jvscj3.js"; + +// src/components/ListRow.tsx +import { effect as _$effect } from "@opentui/solid"; +import { createComponent as _$createComponent } from "@opentui/solid"; +import { insertNode as _$insertNode } from "@opentui/solid"; +import { insert as _$insert } from "@opentui/solid"; +import { setProp as _$setProp } from "@opentui/solid"; +import { createElement as _$createElement } from "@opentui/solid"; +import { TextAttributes } from "@opentui/core"; +import { Show } from "solid-js"; +function ListRow2(props) { + const tone = (fallback) => props.selected ? presets2.select.selectedTextColor : fallback; + return (() => { + var _el$ = _$createElement("box"), _el$2 = _$createElement("box"), _el$3 = _$createElement("box"), _el$4 = _$createElement("text"); + _$insertNode(_el$, _el$2); + _$setProp(_el$, "flexShrink", 0); + _$setProp(_el$, "flexDirection", "column"); + _$setProp(_el$, "paddingLeft", 1); + _$setProp(_el$, "paddingRight", 1); + _$insertNode(_el$2, _el$3); + _$setProp(_el$2, "flexDirection", "row"); + _$setProp(_el$2, "justifyContent", "space-between"); + _$setProp(_el$2, "alignItems", "center"); + _$setProp(_el$2, "height", 1); + _$insertNode(_el$3, _el$4); + _$setProp(_el$3, "flexGrow", 1); + _$setProp(_el$3, "flexShrink", 1); + _$setProp(_el$3, "minWidth", 0); + _$setProp(_el$3, "marginRight", 1); + _$setProp(_el$3, "overflow", "hidden"); + _$setProp(_el$4, "wrapMode", "none"); + _$insert(_el$4, () => props.label); + _$insert(_el$2, _$createComponent(Show, { + get when() { + return props.right; + }, + get children() { + var _el$5 = _$createElement("box"); + _$setProp(_el$5, "flexShrink", 0); + _$setProp(_el$5, "flexDirection", "row"); + _$setProp(_el$5, "alignItems", "center"); + _$insert(_el$5, () => props.right?.(tone)); + return _el$5; + } + }), null); + _$insert(_el$, () => props.below?.(tone), null); + _$effect((_p$) => { + var _v$ = props.id, _v$2 = props.selected ? presets2.select.selectedBackgroundColor : "transparent", _v$3 = theme2.mouse && props.onClick ? () => props.onClick?.() : undefined, _v$4 = tone(), _v$5 = props.bold ? TextAttributes.BOLD : undefined; + _v$ !== _p$.e && (_p$.e = _$setProp(_el$, "id", _v$, _p$.e)); + _v$2 !== _p$.t && (_p$.t = _$setProp(_el$, "backgroundColor", _v$2, _p$.t)); + _v$3 !== _p$.a && (_p$.a = _$setProp(_el$, "onMouseDown", _v$3, _p$.a)); + _v$4 !== _p$.o && (_p$.o = _$setProp(_el$4, "fg", _v$4, _p$.o)); + _v$5 !== _p$.i && (_p$.i = _$setProp(_el$4, "attributes", _v$5, _p$.i)); + return _p$; + }, { + e: undefined, + t: undefined, + a: undefined, + o: undefined, + i: undefined + }); + return _el$; + })(); +} + +export { ListRow2 }; diff --git a/dist/chunk-t2cszvff.js b/dist/chunk-t2cszvff.js new file mode 100644 index 0000000..f830792 --- /dev/null +++ b/dist/chunk-t2cszvff.js @@ -0,0 +1,140 @@ +// @bun +import { + theme2 +} from "./chunk-p6jvscj3.js"; + +// src/components/Modal.tsx +import { insertNode as _$insertNode } from "@opentui/solid"; +import { effect as _$effect } from "@opentui/solid"; +import { insert as _$insert } from "@opentui/solid"; +import { use as _$use } from "@opentui/solid"; +import { setProp as _$setProp } from "@opentui/solid"; +import { createElement as _$createElement } from "@opentui/solid"; +import { createComponent as _$createComponent } from "@opentui/solid"; +import { RGBA } from "@opentui/core"; +import { useBindings } from "@opentui/keymap/solid"; +import { Portal, useRenderer, useTerminalDimensions } from "@opentui/solid"; +import { createSignal, onCleanup, onMount, Show } from "solid-js"; +function Modal2(props) { + return _$createComponent(Portal, { + get children() { + return _$createComponent(Show, { + get when() { + return props.open; + }, + get children() { + return _$createComponent(ModalPanel, props); + } + }); + } + }); +} +function ModalPanel(props) { + const renderer = useRenderer(); + const dimensions = useTerminalDimensions(); + const [panel, setPanel] = createSignal(); + const screenCap = () => Math.max(5, dimensions().height - 4); + const maxPanelHeight = () => Math.min(props.maxHeight ?? screenCap(), screenCap()); + const maxContentHeight = () => Math.max(1, maxPanelHeight() - 4); + const maxPanelWidth = () => Math.max(10, dimensions().width - 4); + const panelWidth = () => Math.min(props.width ?? 50, maxPanelWidth()); + let previousFocus = null; + onMount(() => { + previousFocus = renderer.currentFocusedRenderable; + props.onOpen?.(previousFocus); + panel()?.focus(); + }); + onCleanup(() => { + if (previousFocus && !previousFocus.isDestroyed) + previousFocus.focus(); + }); + const dismissKey = props.dismissKey ?? "escape"; + if (dismissKey !== false || props.commands || props.bindings) { + useBindings(() => ({ + target: panel, + commands: [...dismissKey !== false ? [{ + name: "modal_dismiss", + desc: "close", + shortHelp: true, + run: () => props.onDismiss?.() + }] : [], ...props.commands ?? []], + bindings: [...dismissKey !== false ? [{ + key: dismissKey, + cmd: "modal_dismiss" + }] : [], ...props.bindings ?? []] + })); + } + return (() => { + var _el$ = _$createElement("box"), _el$2 = _$createElement("box"); + _$insertNode(_el$, _el$2); + _$setProp(_el$, "position", "absolute"); + _$setProp(_el$, "top", 0); + _$setProp(_el$, "left", 0); + _$setProp(_el$, "alignItems", "center"); + _$setProp(_el$, "justifyContent", "center"); + _$setProp(_el$, "zIndex", 2000); + _$use(setPanel, _el$2); + _$setProp(_el$2, "focusable", true); + _$setProp(_el$2, "border", true); + _$setProp(_el$2, "flexDirection", "column"); + _$setProp(_el$2, "paddingLeft", 2); + _$setProp(_el$2, "paddingRight", 2); + _$setProp(_el$2, "paddingTop", 1); + _$setProp(_el$2, "paddingBottom", 1); + _$insert(_el$2, _$createComponent(Show, { + get when() { + return props.scrollable; + }, + get fallback() { + return (() => { + var _el$4 = _$createElement("box"); + _$setProp(_el$4, "flexDirection", "column"); + _$setProp(_el$4, "overflow", "hidden"); + _$insert(_el$4, () => props.children); + _$effect((_$p) => _$setProp(_el$4, "maxHeight", maxContentHeight(), _$p)); + return _el$4; + })(); + }, + get children() { + var _el$3 = _$createElement("scrollbox"); + _$setProp(_el$3, "flexShrink", 1); + _$setProp(_el$3, "scrollY", true); + _$setProp(_el$3, "scrollX", false); + _$setProp(_el$3, "focusable", false); + _$insert(_el$3, () => props.children); + _$effect((_$p) => _$setProp(_el$3, "maxHeight", maxContentHeight(), _$p)); + return _el$3; + } + })); + _$effect((_p$) => { + var _v$ = dimensions().width, _v$2 = dimensions().height, _v$3 = props.backdropColor ?? RGBA.fromInts(0, 0, 0, 150), _v$4 = theme2.mouse ? props.onDismiss : undefined, _v$5 = panelWidth(), _v$6 = maxPanelHeight(), _v$7 = theme2.borderStyle, _v$8 = props.accentColor ?? theme2.primary, _v$9 = props.accentColor ?? theme2.primary, _v$0 = props.backgroundColor ?? theme2.background, _v$1 = theme2.mouse ? (event) => event.stopPropagation() : undefined; + _v$ !== _p$.e && (_p$.e = _$setProp(_el$, "width", _v$, _p$.e)); + _v$2 !== _p$.t && (_p$.t = _$setProp(_el$, "height", _v$2, _p$.t)); + _v$3 !== _p$.a && (_p$.a = _$setProp(_el$, "backgroundColor", _v$3, _p$.a)); + _v$4 !== _p$.o && (_p$.o = _$setProp(_el$, "onMouseDown", _v$4, _p$.o)); + _v$5 !== _p$.i && (_p$.i = _$setProp(_el$2, "width", _v$5, _p$.i)); + _v$6 !== _p$.n && (_p$.n = _$setProp(_el$2, "maxHeight", _v$6, _p$.n)); + _v$7 !== _p$.s && (_p$.s = _$setProp(_el$2, "borderStyle", _v$7, _p$.s)); + _v$8 !== _p$.h && (_p$.h = _$setProp(_el$2, "borderColor", _v$8, _p$.h)); + _v$9 !== _p$.r && (_p$.r = _$setProp(_el$2, "focusedBorderColor", _v$9, _p$.r)); + _v$0 !== _p$.d && (_p$.d = _$setProp(_el$2, "backgroundColor", _v$0, _p$.d)); + _v$1 !== _p$.l && (_p$.l = _$setProp(_el$2, "onMouseDown", _v$1, _p$.l)); + return _p$; + }, { + e: undefined, + t: undefined, + a: undefined, + o: undefined, + i: undefined, + n: undefined, + s: undefined, + h: undefined, + r: undefined, + d: undefined, + l: undefined + }); + return _el$; + })(); +} + +export { Modal2 }; diff --git a/dist/chunk-dctn29v0.js b/dist/chunk-tz3vvffs.js similarity index 85% rename from dist/chunk-dctn29v0.js rename to dist/chunk-tz3vvffs.js index 4ae3349..0d992e5 100644 --- a/dist/chunk-dctn29v0.js +++ b/dist/chunk-tz3vvffs.js @@ -1,7 +1,7 @@ // @bun import { - theme -} from "./chunk-x7m82z3z.js"; + theme2 +} from "./chunk-p6jvscj3.js"; // src/components/SignalBars.tsx import { effect as _$effect } from "@opentui/solid"; @@ -11,7 +11,7 @@ import { setProp as _$setProp } from "@opentui/solid"; import { createElement as _$createElement } from "@opentui/solid"; import { For } from "solid-js"; var BARS = ["\u2581", "\u2583", "\u2585", "\u2587"]; -function SignalBars(props) { +function SignalBars2(props) { const level = () => Math.floor(props.signal * BARS.length / 100); return (() => { var _el$ = _$createElement("box"); @@ -21,7 +21,7 @@ function SignalBars(props) { children: (bar, i) => (() => { var _el$2 = _$createElement("text"); _$insert(_el$2, bar); - _$effect((_$p) => _$setProp(_el$2, "fg", i() < level() ? props.filledColor : props.emptyColor ?? theme.muted, _$p)); + _$effect((_$p) => _$setProp(_el$2, "fg", i() < level() ? props.filledColor : props.emptyColor ?? theme2.muted, _$p)); return _el$2; })() })); @@ -29,4 +29,4 @@ function SignalBars(props) { })(); } -export { SignalBars }; +export { SignalBars2 }; diff --git a/dist/chunk-bscbaa87.js b/dist/chunk-v9cetqzr.js similarity index 90% rename from dist/chunk-bscbaa87.js rename to dist/chunk-v9cetqzr.js index 7d0feb7..6d6de31 100644 --- a/dist/chunk-bscbaa87.js +++ b/dist/chunk-v9cetqzr.js @@ -1,7 +1,7 @@ // @bun import { - theme -} from "./chunk-x7m82z3z.js"; + theme2 +} from "./chunk-p6jvscj3.js"; // src/components/Badge.tsx import { insert as _$insert } from "@opentui/solid"; @@ -14,11 +14,11 @@ import { setProp as _$setProp } from "@opentui/solid"; import { createElement as _$createElement } from "@opentui/solid"; import { TextAttributes } from "@opentui/core"; import { Show } from "solid-js"; -function Badge(props) { - const textColor = () => props.textColor ?? theme.background; - const backgroundColor = () => props.backgroundColor ?? theme.background; +function Badge2(props) { + const textColor = () => props.textColor ?? theme2.background; + const backgroundColor = () => props.backgroundColor ?? theme2.background; const attributes = () => props.bold === false ? undefined : TextAttributes.BOLD; - const nerdFonts = () => props.withNerdfont ?? theme.nerdFonts; + const nerdFonts = () => props.withNerdfont ?? theme2.nerdFonts; return (() => { var _el$ = _$createElement("box"), _el$4 = _$createElement("text"); _$insertNode(_el$, _el$4); @@ -80,4 +80,4 @@ function Badge(props) { })(); } -export { Badge }; +export { Badge2 }; diff --git a/dist/chunk-vazj633p.js b/dist/chunk-vazj633p.js new file mode 100644 index 0000000..cba89ae --- /dev/null +++ b/dist/chunk-vazj633p.js @@ -0,0 +1,42 @@ +// @bun +import { + useFocusWithin2 +} from "./chunk-59dzyjgd.js"; + +// src/components/Pane.tsx +import { createComponent as _$createComponent } from "@opentui/solid"; +import { insert as _$insert } from "@opentui/solid"; +import { use as _$use } from "@opentui/solid"; +import { spread as _$spread } from "@opentui/solid"; +import { createElement as _$createElement } from "@opentui/solid"; +import { createContext, createSignal, splitProps, useContext } from "solid-js"; +var PaneContext = createContext(); +function Pane2(props) { + const [local, rest] = splitProps(props, ["handle", "children"]); + const [el, setEl] = createSignal(); + const focused = useFocusWithin2(el); + const handle = { + target: el, + focused, + focus: () => el()?.focus() + }; + local.handle?.(handle); + return _$createComponent(PaneContext.Provider, { + value: handle, + get children() { + var _el$ = _$createElement("box"); + _$use(setEl, _el$); + _$spread(_el$, rest, true); + _$insert(_el$, () => local.children); + return _el$; + } + }); +} +function usePane2() { + const pane = useContext(PaneContext); + if (!pane) + throw new Error("usePane() must be used inside a "); + return pane; +} + +export { Pane2, usePane2 }; diff --git a/dist/chunk-ev4wvhd2.js b/dist/chunk-vf2ybhtx.js similarity index 93% rename from dist/chunk-ev4wvhd2.js rename to dist/chunk-vf2ybhtx.js index e3e8901..66f9d8b 100644 --- a/dist/chunk-ev4wvhd2.js +++ b/dist/chunk-vf2ybhtx.js @@ -1,7 +1,7 @@ // @bun import { - theme -} from "./chunk-x7m82z3z.js"; + theme2 +} from "./chunk-p6jvscj3.js"; // src/components/Tabs.tsx import { effect as _$effect } from "@opentui/solid"; @@ -14,7 +14,7 @@ import { createElement as _$createElement } from "@opentui/solid"; import { BorderChars, CliRenderEvents, TextAttributes } from "@opentui/core"; import { onResize, useRenderer } from "@opentui/solid"; import { createMemo, createSignal, Index } from "solid-js"; -function stepTabValue(items, value, delta) { +function stepTabValue2(items, value, delta) { const index = items.findIndex((t) => t.value === value); if (index === -1) return value; @@ -58,7 +58,7 @@ function fitCount(items, start, available) { } return Math.max(count, 1); } -function Tabs(props) { +function Tabs2(props) { const renderer = useRenderer(); const [width, setWidth] = createSignal(0); let container; @@ -98,10 +98,10 @@ function Tabs(props) { } return shown; }); - const accent = () => props.accentColor ?? theme.primary; - const muted = () => props.mutedColor ?? theme.muted; + const accent = () => props.accentColor ?? theme2.primary; + const muted = () => props.mutedColor ?? theme2.muted; const borderColor = () => props.focused ? accent() : muted(); - const chars = BorderChars[theme.borderStyle]; + const chars = BorderChars[theme2.borderStyle]; return (() => { var _el$ = _$createElement("box"), _el$2 = _$createElement("text"), _el$3 = _$createElement("box"), _el$4 = _$createElement("text"); _$insertNode(_el$, _el$2); @@ -131,7 +131,7 @@ function Tabs(props) { _$setProp(_el$6, "selectable", false); _$insert(_el$6, () => ` ${s().label} `); _$effect((_p$) => { - var _v$3 = s().isActive ? accent() : muted(), _v$4 = s().isActive ? TextAttributes.BOLD : undefined, _v$5 = theme.mouse && s().value !== undefined ? () => props.onChange(s().value) : undefined; + var _v$3 = s().isActive ? accent() : muted(), _v$4 = s().isActive ? TextAttributes.BOLD : undefined, _v$5 = theme2.mouse && s().value !== undefined ? () => props.onChange(s().value) : undefined; _v$3 !== _p$.e && (_p$.e = _$setProp(_el$6, "fg", _v$3, _p$.e)); _v$4 !== _p$.t && (_p$.t = _$setProp(_el$6, "attributes", _v$4, _p$.t)); _v$5 !== _p$.a && (_p$.a = _$setProp(_el$6, "onMouseDown", _v$5, _p$.a)); @@ -165,4 +165,4 @@ function Tabs(props) { })(); } -export { stepTabValue, Tabs }; +export { stepTabValue2, Tabs2 }; diff --git a/dist/chunk-wtbg0e39.js b/dist/chunk-wtbg0e39.js new file mode 100644 index 0000000..662b827 --- /dev/null +++ b/dist/chunk-wtbg0e39.js @@ -0,0 +1,52 @@ +// @bun +import { + theme2 +} from "./chunk-p6jvscj3.js"; +import { + Box2 +} from "./chunk-8r4rajaz.js"; +import { + Tabs2 +} from "./chunk-vf2ybhtx.js"; + +// src/components/TabbedPanel.tsx +import { insert as _$insert } from "@opentui/solid"; +import { memo as _$memo } from "@opentui/solid"; +import { createComponent as _$createComponent } from "@opentui/solid"; +import { setProp as _$setProp } from "@opentui/solid"; +import { createElement as _$createElement } from "@opentui/solid"; +function TabbedPanel2(props) { + return (() => { + var _el$ = _$createElement("box"); + _$setProp(_el$, "flexDirection", "column"); + _$setProp(_el$, "flexGrow", 1); + _$insert(_el$, _$createComponent(Tabs2, { + get items() { + return props.items; + }, + get value() { + return props.value; + }, + get onChange() { + return props.onChange; + }, + get focused() { + return props.focused; + } + }), null); + _$insert(_el$, _$createComponent(Box2, { + flexGrow: 1, + border: ["left", "right", "bottom"], + get borderColor() { + return _$memo(() => !!props.focused)() ? theme2.primary : theme2.muted; + }, + flexDirection: "column", + get children() { + return props.children; + } + }), null); + return _el$; + })(); +} + +export { TabbedPanel2 }; diff --git a/dist/chunk-x7m82z3z.js b/dist/chunk-x7m82z3z.js deleted file mode 100644 index 87166d7..0000000 --- a/dist/chunk-x7m82z3z.js +++ /dev/null @@ -1,45 +0,0 @@ -// @bun -import { - configPath, - readYamlFile -} from "./chunk-7f8jagy5.js"; -import { - mergeConfig, - normalizeColors, - resolveBorderStyle -} from "./chunk-hcq62p48.js"; -import { - buildPresets -} from "./chunk-cnhhssmz.js"; - -// src/index.ts -import { join } from "path"; -function buildTheme() { - const defaultConfigPath = join(import.meta.dir, "default.yaml"); - const base = readYamlFile(defaultConfigPath) ?? {}; - const user = readYamlFile(configPath()) ?? {}; - const merged = mergeConfig(base, user); - const colors = normalizeColors(merged.colors); - return { - ...colors, - background: colors.base00, - subtleBg: colors.base01, - selection: colors.base02, - subtle: colors.base03, - muted: colors.base04, - text: colors.base05, - primary: colors.base0d, - success: colors.base0b, - warning: colors.base09, - error: colors.base08, - nerdFonts: merged.nerdFonts, - emojiFonts: merged.emojiFonts, - reducedMotion: merged.reducedMotion, - mouse: merged.mouse, - borderStyle: resolveBorderStyle(merged.border) - }; -} -var theme = buildTheme(); -var presets = buildPresets(theme); - -export { theme, presets }; diff --git a/dist/chunk-xykm10y9.js b/dist/chunk-xykm10y9.js new file mode 100644 index 0000000..4651581 --- /dev/null +++ b/dist/chunk-xykm10y9.js @@ -0,0 +1,10 @@ +// @bun +// src/yaml.ts +import { homedir } from "os"; +import { join } from "path"; +function configPath2() { + const configDir = process.env.XDG_CONFIG_HOME || join(homedir(), ".config"); + return join(configDir, "ilovetui", "config.yaml"); +} + +export { configPath2 }; diff --git a/dist/chunk-cnhhssmz.js b/dist/chunk-yyg967q8.js similarity index 95% rename from dist/chunk-cnhhssmz.js rename to dist/chunk-yyg967q8.js index 07443d9..ed9759c 100644 --- a/dist/chunk-cnhhssmz.js +++ b/dist/chunk-yyg967q8.js @@ -1,6 +1,6 @@ // @bun // src/presets.ts -function buildPresets(theme) { +function buildPresets2(theme) { const select = { backgroundColor: theme.background, textColor: theme.text, @@ -41,4 +41,4 @@ function buildPresets(theme) { return { select, tabSelect, input, textarea: input, box, slider }; } -export { buildPresets }; +export { buildPresets2 }; diff --git a/dist/chunk-5m64a9kb.js b/dist/chunk-z734n0wr.js similarity index 90% rename from dist/chunk-5m64a9kb.js rename to dist/chunk-z734n0wr.js index 372adf8..504b705 100644 --- a/dist/chunk-5m64a9kb.js +++ b/dist/chunk-z734n0wr.js @@ -1,7 +1,7 @@ // @bun import { - theme -} from "./chunk-x7m82z3z.js"; + theme2 +} from "./chunk-p6jvscj3.js"; // src/components/ProgressBar.tsx import { effect as _$effect } from "@opentui/solid"; @@ -23,9 +23,9 @@ function sampleGradient(stops, t) { const [br, bg, bb, ba] = parseColor(stops[i + 1]).toInts(); return RGBA.fromInts(Math.round(ar + (br - ar) * localT), Math.round(ag + (bg - ag) * localT), Math.round(ab + (bb - ab) * localT), Math.round(aa + (ba - aa) * localT)); } -function ProgressBar(props) { +function ProgressBar2(props) { const width = () => props.width ?? 20; - const stops = createMemo(() => Array.isArray(props.color) ? props.color : [props.color ?? theme.primary]); + const stops = createMemo(() => Array.isArray(props.color) ? props.color : [props.color ?? theme2.primary]); const filled = createMemo(() => Math.round(width() * Math.min(Math.max(props.value, 0), 100) / 100)); const cells = createMemo(() => Array.from({ length: width() @@ -46,7 +46,7 @@ function ProgressBar(props) { var _c$ = _$memo(() => !!isFilled()); return () => _c$() ? props.fillChar ?? "\u2588" : props.trackChar ?? "\u2591"; })()); - _$effect((_$p) => _$setProp(_el$2, "fg", isFilled() ? sampleGradient(stops(), t) : props.trackColor ?? theme.muted, _$p)); + _$effect((_$p) => _$setProp(_el$2, "fg", isFilled() ? sampleGradient(stops(), t) : props.trackColor ?? theme2.muted, _$p)); return _el$2; })(); } @@ -55,4 +55,4 @@ function ProgressBar(props) { })(); } -export { ProgressBar }; +export { ProgressBar2 }; diff --git a/dist/chunk-zjfxbvmq.js b/dist/chunk-zjfxbvmq.js deleted file mode 100644 index b05e2f5..0000000 --- a/dist/chunk-zjfxbvmq.js +++ /dev/null @@ -1,100 +0,0 @@ -// @bun -import { - theme -} from "./chunk-x7m82z3z.js"; - -// src/components/Modal.tsx -import { insertNode as _$insertNode } from "@opentui/solid"; -import { createComponent as _$createComponent } from "@opentui/solid"; -import { effect as _$effect } from "@opentui/solid"; -import { insert as _$insert } from "@opentui/solid"; -import { setProp as _$setProp } from "@opentui/solid"; -import { createElement as _$createElement } from "@opentui/solid"; -import { RGBA } from "@opentui/core"; -import { Portal, useTerminalDimensions } from "@opentui/solid"; -import { Show } from "solid-js"; -function Modal(props) { - const dimensions = useTerminalDimensions(); - const screenCap = () => Math.max(5, dimensions().height - 4); - const maxPanelHeight = () => Math.min(props.maxHeight ?? screenCap(), screenCap()); - const maxContentHeight = () => Math.max(1, maxPanelHeight() - 4); - const maxPanelWidth = () => Math.max(10, dimensions().width - 4); - const panelWidth = () => Math.min(props.width ?? 50, maxPanelWidth()); - return _$createComponent(Portal, { - get children() { - return _$createComponent(Show, { - get when() { - return props.open; - }, - get children() { - var _el$ = _$createElement("box"), _el$2 = _$createElement("box"); - _$insertNode(_el$, _el$2); - _$setProp(_el$, "position", "absolute"); - _$setProp(_el$, "top", 0); - _$setProp(_el$, "left", 0); - _$setProp(_el$, "alignItems", "center"); - _$setProp(_el$, "justifyContent", "center"); - _$setProp(_el$, "zIndex", 2000); - _$setProp(_el$2, "border", true); - _$setProp(_el$2, "flexDirection", "column"); - _$setProp(_el$2, "paddingLeft", 2); - _$setProp(_el$2, "paddingRight", 2); - _$setProp(_el$2, "paddingTop", 1); - _$setProp(_el$2, "paddingBottom", 1); - _$insert(_el$2, _$createComponent(Show, { - get when() { - return props.scrollable; - }, - get fallback() { - return (() => { - var _el$4 = _$createElement("box"); - _$setProp(_el$4, "flexDirection", "column"); - _$setProp(_el$4, "overflow", "hidden"); - _$insert(_el$4, () => props.children); - _$effect((_$p) => _$setProp(_el$4, "maxHeight", maxContentHeight(), _$p)); - return _el$4; - })(); - }, - get children() { - var _el$3 = _$createElement("scrollbox"); - _$setProp(_el$3, "flexShrink", 1); - _$setProp(_el$3, "scrollY", true); - _$setProp(_el$3, "scrollX", false); - _$insert(_el$3, () => props.children); - _$effect((_$p) => _$setProp(_el$3, "maxHeight", maxContentHeight(), _$p)); - return _el$3; - } - })); - _$effect((_p$) => { - var _v$ = dimensions().width, _v$2 = dimensions().height, _v$3 = props.backdropColor ?? RGBA.fromInts(0, 0, 0, 150), _v$4 = theme.mouse ? props.onDismiss : undefined, _v$5 = panelWidth(), _v$6 = maxPanelHeight(), _v$7 = theme.borderStyle, _v$8 = props.accentColor ?? theme.primary, _v$9 = props.backgroundColor ?? theme.background, _v$0 = theme.mouse ? (event) => event.stopPropagation() : undefined; - _v$ !== _p$.e && (_p$.e = _$setProp(_el$, "width", _v$, _p$.e)); - _v$2 !== _p$.t && (_p$.t = _$setProp(_el$, "height", _v$2, _p$.t)); - _v$3 !== _p$.a && (_p$.a = _$setProp(_el$, "backgroundColor", _v$3, _p$.a)); - _v$4 !== _p$.o && (_p$.o = _$setProp(_el$, "onMouseDown", _v$4, _p$.o)); - _v$5 !== _p$.i && (_p$.i = _$setProp(_el$2, "width", _v$5, _p$.i)); - _v$6 !== _p$.n && (_p$.n = _$setProp(_el$2, "maxHeight", _v$6, _p$.n)); - _v$7 !== _p$.s && (_p$.s = _$setProp(_el$2, "borderStyle", _v$7, _p$.s)); - _v$8 !== _p$.h && (_p$.h = _$setProp(_el$2, "borderColor", _v$8, _p$.h)); - _v$9 !== _p$.r && (_p$.r = _$setProp(_el$2, "backgroundColor", _v$9, _p$.r)); - _v$0 !== _p$.d && (_p$.d = _$setProp(_el$2, "onMouseDown", _v$0, _p$.d)); - return _p$; - }, { - e: undefined, - t: undefined, - a: undefined, - o: undefined, - i: undefined, - n: undefined, - s: undefined, - h: undefined, - r: undefined, - d: undefined - }); - return _el$; - } - }); - } - }); -} - -export { Modal }; diff --git a/dist/components/Badge.js b/dist/components/Badge.js index 7aad879..52c2150 100644 --- a/dist/components/Badge.js +++ b/dist/components/Badge.js @@ -1,11 +1,12 @@ // @bun import { - Badge -} from "../chunk-bscbaa87.js"; -import"../chunk-x7m82z3z.js"; -import"../chunk-7f8jagy5.js"; -import"../chunk-hcq62p48.js"; -import"../chunk-cnhhssmz.js"; + Badge2 +} from "../chunk-v9cetqzr.js"; +import"../chunk-p6jvscj3.js"; +import"../chunk-yyg967q8.js"; +import"../chunk-njvj322f.js"; +import"../chunk-6ggk5fg7.js"; +import"../chunk-xykm10y9.js"; export { - Badge + Badge2 as Badge }; diff --git a/dist/components/Box.js b/dist/components/Box.js index d358e68..66a2176 100644 --- a/dist/components/Box.js +++ b/dist/components/Box.js @@ -1,11 +1,12 @@ // @bun import { - Box -} from "../chunk-ynqvwj4d.js"; -import"../chunk-x7m82z3z.js"; -import"../chunk-7f8jagy5.js"; -import"../chunk-hcq62p48.js"; -import"../chunk-cnhhssmz.js"; + Box2 +} from "../chunk-8r4rajaz.js"; +import"../chunk-p6jvscj3.js"; +import"../chunk-yyg967q8.js"; +import"../chunk-njvj322f.js"; +import"../chunk-6ggk5fg7.js"; +import"../chunk-xykm10y9.js"; export { - Box + Box2 as Box }; diff --git a/dist/components/HelpBar.js b/dist/components/HelpBar.js index 078f853..a8aa9b8 100644 --- a/dist/components/HelpBar.js +++ b/dist/components/HelpBar.js @@ -1,11 +1,12 @@ // @bun import { - HelpBar -} from "../chunk-rvq53a2a.js"; -import"../chunk-x7m82z3z.js"; -import"../chunk-7f8jagy5.js"; -import"../chunk-hcq62p48.js"; -import"../chunk-cnhhssmz.js"; + HelpBar2 +} from "../chunk-c1dx8cn3.js"; +import"../chunk-p6jvscj3.js"; +import"../chunk-yyg967q8.js"; +import"../chunk-njvj322f.js"; +import"../chunk-6ggk5fg7.js"; +import"../chunk-xykm10y9.js"; export { - HelpBar + HelpBar2 as HelpBar }; diff --git a/dist/components/HelpModal.js b/dist/components/HelpModal.js index 5630e0f..8bfb759 100644 --- a/dist/components/HelpModal.js +++ b/dist/components/HelpModal.js @@ -1,13 +1,14 @@ // @bun import { - HelpModal -} from "../chunk-xxg67vfz.js"; -import"../chunk-zjfxbvmq.js"; -import"../chunk-x7m82z3z.js"; -import"../chunk-7f8jagy5.js"; -import"../chunk-hcq62p48.js"; -import"../chunk-cnhhssmz.js"; -import"../chunk-cyvpvpws.js"; + HelpModal2 +} from "../chunk-ersd5rrs.js"; +import"../chunk-t2cszvff.js"; +import"../chunk-p6jvscj3.js"; +import"../chunk-yyg967q8.js"; +import"../chunk-njvj322f.js"; +import"../chunk-6ggk5fg7.js"; +import"../chunk-xykm10y9.js"; +import"../chunk-ee2qaswx.js"; export { - HelpModal + HelpModal2 as HelpModal }; diff --git a/dist/components/KeyValue.js b/dist/components/KeyValue.js new file mode 100644 index 0000000..a9c9556 --- /dev/null +++ b/dist/components/KeyValue.js @@ -0,0 +1,12 @@ +// @bun +import { + KeyValue2 +} from "../chunk-c4gp0x16.js"; +import"../chunk-p6jvscj3.js"; +import"../chunk-yyg967q8.js"; +import"../chunk-njvj322f.js"; +import"../chunk-6ggk5fg7.js"; +import"../chunk-xykm10y9.js"; +export { + KeyValue2 as KeyValue +}; diff --git a/dist/components/ListRow.js b/dist/components/ListRow.js new file mode 100644 index 0000000..1845351 --- /dev/null +++ b/dist/components/ListRow.js @@ -0,0 +1,12 @@ +// @bun +import { + ListRow2 +} from "../chunk-sh9n4zha.js"; +import"../chunk-p6jvscj3.js"; +import"../chunk-yyg967q8.js"; +import"../chunk-njvj322f.js"; +import"../chunk-6ggk5fg7.js"; +import"../chunk-xykm10y9.js"; +export { + ListRow2 as ListRow +}; diff --git a/dist/components/MinSizeGuard.js b/dist/components/MinSizeGuard.js index 318da10..fde12b0 100644 --- a/dist/components/MinSizeGuard.js +++ b/dist/components/MinSizeGuard.js @@ -1,11 +1,12 @@ // @bun import { - MinSizeGuard -} from "../chunk-eta27h3c.js"; -import"../chunk-x7m82z3z.js"; -import"../chunk-7f8jagy5.js"; -import"../chunk-hcq62p48.js"; -import"../chunk-cnhhssmz.js"; + MinSizeGuard2 +} from "../chunk-qdyd8q9r.js"; +import"../chunk-p6jvscj3.js"; +import"../chunk-yyg967q8.js"; +import"../chunk-njvj322f.js"; +import"../chunk-6ggk5fg7.js"; +import"../chunk-xykm10y9.js"; export { - MinSizeGuard + MinSizeGuard2 as MinSizeGuard }; diff --git a/dist/components/Modal.js b/dist/components/Modal.js index 4139538..70f7914 100644 --- a/dist/components/Modal.js +++ b/dist/components/Modal.js @@ -1,11 +1,12 @@ // @bun import { - Modal -} from "../chunk-zjfxbvmq.js"; -import"../chunk-x7m82z3z.js"; -import"../chunk-7f8jagy5.js"; -import"../chunk-hcq62p48.js"; -import"../chunk-cnhhssmz.js"; + Modal2 +} from "../chunk-t2cszvff.js"; +import"../chunk-p6jvscj3.js"; +import"../chunk-yyg967q8.js"; +import"../chunk-njvj322f.js"; +import"../chunk-6ggk5fg7.js"; +import"../chunk-xykm10y9.js"; export { - Modal + Modal2 as Modal }; diff --git a/dist/components/NotificationHost.js b/dist/components/NotificationHost.js index 2ccf1c5..d6d59c1 100644 --- a/dist/components/NotificationHost.js +++ b/dist/components/NotificationHost.js @@ -1,12 +1,12 @@ // @bun import { - NotificationHost -} from "../chunk-fqzxyvhv.js"; -import"../chunk-x7m82z3z.js"; -import"../chunk-7f8jagy5.js"; -import"../chunk-hcq62p48.js"; -import"../chunk-cnhhssmz.js"; -import"../chunk-y6txxzxk.js"; + NotificationHost2 +} from "../chunk-ajb193xj.js"; +import"../chunk-p6jvscj3.js"; +import"../chunk-yyg967q8.js"; +import"../chunk-njvj322f.js"; +import"../chunk-6ggk5fg7.js"; +import"../chunk-xykm10y9.js"; export { - NotificationHost + NotificationHost2 as NotificationHost }; diff --git a/dist/components/Pane.js b/dist/components/Pane.js new file mode 100644 index 0000000..3e132b6 --- /dev/null +++ b/dist/components/Pane.js @@ -0,0 +1,10 @@ +// @bun +import { + Pane2, + usePane2 +} from "../chunk-vazj633p.js"; +import"../chunk-59dzyjgd.js"; +export { + Pane2 as Pane, + usePane2 as usePane +}; diff --git a/dist/components/ProgressBar.js b/dist/components/ProgressBar.js index baeb011..eb2887c 100644 --- a/dist/components/ProgressBar.js +++ b/dist/components/ProgressBar.js @@ -1,11 +1,12 @@ // @bun import { - ProgressBar -} from "../chunk-5m64a9kb.js"; -import"../chunk-x7m82z3z.js"; -import"../chunk-7f8jagy5.js"; -import"../chunk-hcq62p48.js"; -import"../chunk-cnhhssmz.js"; + ProgressBar2 +} from "../chunk-z734n0wr.js"; +import"../chunk-p6jvscj3.js"; +import"../chunk-yyg967q8.js"; +import"../chunk-njvj322f.js"; +import"../chunk-6ggk5fg7.js"; +import"../chunk-xykm10y9.js"; export { - ProgressBar + ProgressBar2 as ProgressBar }; diff --git a/dist/components/SectionHeader.js b/dist/components/SectionHeader.js new file mode 100644 index 0000000..550a30d --- /dev/null +++ b/dist/components/SectionHeader.js @@ -0,0 +1,81 @@ +// @bun +import"../chunk-njvj322f.js"; +import"../chunk-6ggk5fg7.js"; +import"../chunk-yyg967q8.js"; +import"../chunk-xykm10y9.js"; +import { + theme2 +} from "../chunk-p6jvscj3.js"; +import { + Spinner2 +} from "../chunk-kmqqzz9e.js"; + +// src/components/SectionHeader.tsx +import { createTextNode as _$createTextNode } from "@opentui/solid"; +import { createComponent as _$createComponent } from "@opentui/solid"; +import { effect as _$effect } from "@opentui/solid"; +import { insertNode as _$insertNode } from "@opentui/solid"; +import { insert as _$insert } from "@opentui/solid"; +import { memo as _$memo } from "@opentui/solid"; +import { setProp as _$setProp } from "@opentui/solid"; +import { createElement as _$createElement } from "@opentui/solid"; +import { TextAttributes } from "@opentui/core"; +import { Show } from "solid-js"; +function SectionHeader(props) { + return (() => { + var _el$ = _$createElement("box"), _el$2 = _$createElement("box"), _el$3 = _$createElement("text"), _el$4 = _$createElement("box"); + _$insertNode(_el$, _el$2); + _$insertNode(_el$, _el$4); + _$setProp(_el$, "flexShrink", 0); + _$setProp(_el$, "flexDirection", "row"); + _$setProp(_el$, "justifyContent", "space-between"); + _$setProp(_el$, "alignItems", "center"); + _$setProp(_el$, "height", 1); + _$insertNode(_el$2, _el$3); + _$setProp(_el$2, "flexGrow", 1); + _$setProp(_el$2, "flexShrink", 1); + _$setProp(_el$2, "minWidth", 0); + _$setProp(_el$2, "marginRight", 1); + _$setProp(_el$2, "overflow", "hidden"); + _$setProp(_el$3, "wrapMode", "none"); + _$insert(_el$3, () => props.title ?? ""); + _$setProp(_el$4, "flexShrink", 0); + _$insert(_el$4, _$createComponent(Show, { + get when() { + return !props.loading; + }, + get fallback() { + return (() => { + var _el$6 = _$createElement("box"), _el$7 = _$createElement("text"), _el$8 = _$createTextNode(` `); + _$insertNode(_el$6, _el$7); + _$setProp(_el$6, "flexDirection", "row"); + _$setProp(_el$6, "alignItems", "center"); + _$insert(_el$6, _$createComponent(Spinner2, {}), _el$7); + _$insertNode(_el$7, _el$8); + _$insert(_el$7, () => props.loadingLabel ?? "Loading\u2026", null); + _$effect((_$p) => _$setProp(_el$7, "fg", theme2.muted, _$p)); + return _el$6; + })(); + }, + get children() { + var _el$5 = _$createElement("text"); + _$insert(_el$5, () => props.hint ?? ""); + _$effect((_$p) => _$setProp(_el$5, "fg", theme2.muted, _$p)); + return _el$5; + } + })); + _$effect((_p$) => { + var _v$ = theme2.muted, _v$2 = TextAttributes.BOLD; + _v$ !== _p$.e && (_p$.e = _$setProp(_el$3, "fg", _v$, _p$.e)); + _v$2 !== _p$.t && (_p$.t = _$setProp(_el$3, "attributes", _v$2, _p$.t)); + return _p$; + }, { + e: undefined, + t: undefined + }); + return _el$; + })(); +} +export { + SectionHeader +}; diff --git a/dist/components/Sidebar.js b/dist/components/Sidebar.js index 95e2fc4..d8cd598 100644 --- a/dist/components/Sidebar.js +++ b/dist/components/Sidebar.js @@ -1,11 +1,12 @@ // @bun import { - Sidebar -} from "../chunk-15vweq1q.js"; -import"../chunk-x7m82z3z.js"; -import"../chunk-7f8jagy5.js"; -import"../chunk-hcq62p48.js"; -import"../chunk-cnhhssmz.js"; + Sidebar2 +} from "../chunk-rcywynbw.js"; +import"../chunk-p6jvscj3.js"; +import"../chunk-yyg967q8.js"; +import"../chunk-njvj322f.js"; +import"../chunk-6ggk5fg7.js"; +import"../chunk-xykm10y9.js"; export { - Sidebar + Sidebar2 as Sidebar }; diff --git a/dist/components/SignalBars.js b/dist/components/SignalBars.js index 14e8e58..0df8002 100644 --- a/dist/components/SignalBars.js +++ b/dist/components/SignalBars.js @@ -1,11 +1,12 @@ // @bun import { - SignalBars -} from "../chunk-dctn29v0.js"; -import"../chunk-x7m82z3z.js"; -import"../chunk-7f8jagy5.js"; -import"../chunk-hcq62p48.js"; -import"../chunk-cnhhssmz.js"; + SignalBars2 +} from "../chunk-tz3vvffs.js"; +import"../chunk-p6jvscj3.js"; +import"../chunk-yyg967q8.js"; +import"../chunk-njvj322f.js"; +import"../chunk-6ggk5fg7.js"; +import"../chunk-xykm10y9.js"; export { - SignalBars + SignalBars2 as SignalBars }; diff --git a/dist/components/Spinner.js b/dist/components/Spinner.js index b0475f6..bdd2d08 100644 --- a/dist/components/Spinner.js +++ b/dist/components/Spinner.js @@ -1,39 +1,12 @@ // @bun import { - theme -} from "../chunk-x7m82z3z.js"; -import"../chunk-7f8jagy5.js"; -import"../chunk-hcq62p48.js"; -import"../chunk-cnhhssmz.js"; - -// src/components/Spinner.tsx -import { setProp as _$setProp } from "@opentui/solid"; -import { effect as _$effect } from "@opentui/solid"; -import { createElement as _$createElement } from "@opentui/solid"; -import"opentui-spinner/solid"; -function Spinner(props) { - return (() => { - var _el$ = _$createElement("spinner"); - _$effect((_p$) => { - var { name: _v$, frames: _v$2, interval: _v$3 } = props, _v$4 = props.autoplay ?? !theme.reducedMotion, _v$5 = props.color ?? theme.primary, _v$6 = props.backgroundColor; - _v$ !== _p$.e && (_p$.e = _$setProp(_el$, "name", _v$, _p$.e)); - _v$2 !== _p$.t && (_p$.t = _$setProp(_el$, "frames", _v$2, _p$.t)); - _v$3 !== _p$.a && (_p$.a = _$setProp(_el$, "interval", _v$3, _p$.a)); - _v$4 !== _p$.o && (_p$.o = _$setProp(_el$, "autoplay", _v$4, _p$.o)); - _v$5 !== _p$.i && (_p$.i = _$setProp(_el$, "color", _v$5, _p$.i)); - _v$6 !== _p$.n && (_p$.n = _$setProp(_el$, "backgroundColor", _v$6, _p$.n)); - return _p$; - }, { - e: undefined, - t: undefined, - a: undefined, - o: undefined, - i: undefined, - n: undefined - }); - return _el$; - })(); -} + Spinner2 +} from "../chunk-kmqqzz9e.js"; +import"../chunk-p6jvscj3.js"; +import"../chunk-yyg967q8.js"; +import"../chunk-njvj322f.js"; +import"../chunk-6ggk5fg7.js"; +import"../chunk-xykm10y9.js"; export { - Spinner + Spinner2 as Spinner }; diff --git a/dist/components/TabbedPanel.js b/dist/components/TabbedPanel.js new file mode 100644 index 0000000..aac1c7a --- /dev/null +++ b/dist/components/TabbedPanel.js @@ -0,0 +1,14 @@ +// @bun +import { + TabbedPanel2 +} from "../chunk-wtbg0e39.js"; +import"../chunk-vf2ybhtx.js"; +import"../chunk-8r4rajaz.js"; +import"../chunk-p6jvscj3.js"; +import"../chunk-yyg967q8.js"; +import"../chunk-njvj322f.js"; +import"../chunk-6ggk5fg7.js"; +import"../chunk-xykm10y9.js"; +export { + TabbedPanel2 as TabbedPanel +}; diff --git a/dist/components/Tabs.js b/dist/components/Tabs.js index 32f5f7f..fd03727 100644 --- a/dist/components/Tabs.js +++ b/dist/components/Tabs.js @@ -1,13 +1,14 @@ // @bun import { - Tabs, - stepTabValue -} from "../chunk-ev4wvhd2.js"; -import"../chunk-x7m82z3z.js"; -import"../chunk-7f8jagy5.js"; -import"../chunk-hcq62p48.js"; -import"../chunk-cnhhssmz.js"; + stepTabValue2, + Tabs2 +} from "../chunk-vf2ybhtx.js"; +import"../chunk-p6jvscj3.js"; +import"../chunk-yyg967q8.js"; +import"../chunk-njvj322f.js"; +import"../chunk-6ggk5fg7.js"; +import"../chunk-xykm10y9.js"; export { - stepTabValue, - Tabs + Tabs2 as Tabs, + stepTabValue2 as stepTabValue }; diff --git a/dist/components/Toggle.js b/dist/components/Toggle.js index d399c4f..9016d81 100644 --- a/dist/components/Toggle.js +++ b/dist/components/Toggle.js @@ -1,12 +1,13 @@ // @bun import { - Toggle -} from "../chunk-mezyz219.js"; -import"../chunk-bscbaa87.js"; -import"../chunk-x7m82z3z.js"; -import"../chunk-7f8jagy5.js"; -import"../chunk-hcq62p48.js"; -import"../chunk-cnhhssmz.js"; + Toggle2 +} from "../chunk-qhp6k176.js"; +import"../chunk-v9cetqzr.js"; +import"../chunk-p6jvscj3.js"; +import"../chunk-yyg967q8.js"; +import"../chunk-njvj322f.js"; +import"../chunk-6ggk5fg7.js"; +import"../chunk-xykm10y9.js"; export { - Toggle + Toggle2 as Toggle }; diff --git a/dist/components/help.js b/dist/components/help.js index 53aa456..0e61665 100644 --- a/dist/components/help.js +++ b/dist/components/help.js @@ -1,17 +1,18 @@ // @bun +import"../chunk-njvj322f.js"; +import"../chunk-6ggk5fg7.js"; +import"../chunk-yyg967q8.js"; +import"../chunk-xykm10y9.js"; +import"../chunk-p6jvscj3.js"; import { - HelpModal -} from "../chunk-xxg67vfz.js"; -import"../chunk-zjfxbvmq.js"; + HelpBar2 +} from "../chunk-c1dx8cn3.js"; +import"../chunk-ee2qaswx.js"; +import"../chunk-t2cszvff.js"; import { - HelpBar -} from "../chunk-rvq53a2a.js"; -import"../chunk-x7m82z3z.js"; -import"../chunk-7f8jagy5.js"; -import"../chunk-hcq62p48.js"; -import"../chunk-cnhhssmz.js"; -import"../chunk-cyvpvpws.js"; + HelpModal2 +} from "../chunk-ersd5rrs.js"; export { - HelpModal, - HelpBar + HelpBar2 as HelpBar, + HelpModal2 as HelpModal }; diff --git a/dist/components/index.js b/dist/components/index.js index 3bfd6c8..46e4276 100644 --- a/dist/components/index.js +++ b/dist/components/index.js @@ -1,50 +1,69 @@ // @bun +import"../chunk-njvj322f.js"; +import"../chunk-6ggk5fg7.js"; +import"../chunk-yyg967q8.js"; +import"../chunk-xykm10y9.js"; +import"../chunk-p6jvscj3.js"; import { - NotificationHost -} from "../chunk-fqzxyvhv.js"; + Badge2 +} from "../chunk-v9cetqzr.js"; import { - Sidebar -} from "../chunk-15vweq1q.js"; + Box2 +} from "../chunk-8r4rajaz.js"; import { - Toggle -} from "../chunk-mezyz219.js"; + KeyValue2 +} from "../chunk-c4gp0x16.js"; import { - MinSizeGuard -} from "../chunk-eta27h3c.js"; + ListRow2 +} from "../chunk-sh9n4zha.js"; import { - Tabs, - stepTabValue -} from "../chunk-ev4wvhd2.js"; + MinSizeGuard2 +} from "../chunk-qdyd8q9r.js"; import { - Box -} from "../chunk-ynqvwj4d.js"; + Modal2 +} from "../chunk-t2cszvff.js"; import { - Modal -} from "../chunk-zjfxbvmq.js"; + NotificationHost2 +} from "../chunk-ajb193xj.js"; +import"../chunk-59dzyjgd.js"; import { - Badge -} from "../chunk-bscbaa87.js"; + Pane2, + usePane2 +} from "../chunk-vazj633p.js"; import { - ProgressBar -} from "../chunk-5m64a9kb.js"; + ProgressBar2 +} from "../chunk-z734n0wr.js"; import { - SignalBars -} from "../chunk-dctn29v0.js"; -import"../chunk-x7m82z3z.js"; -import"../chunk-7f8jagy5.js"; -import"../chunk-hcq62p48.js"; -import"../chunk-cnhhssmz.js"; -import"../chunk-y6txxzxk.js"; + Sidebar2 +} from "../chunk-rcywynbw.js"; +import { + SignalBars2 +} from "../chunk-tz3vvffs.js"; +import { + stepTabValue2, + Tabs2 +} from "../chunk-vf2ybhtx.js"; +import { + TabbedPanel2 +} from "../chunk-wtbg0e39.js"; +import { + Toggle2 +} from "../chunk-qhp6k176.js"; export { - stepTabValue, - Toggle, - Tabs, - SignalBars, - Sidebar, - ProgressBar, - NotificationHost, - Modal, - MinSizeGuard, - Box, - Badge + Badge2 as Badge, + Box2 as Box, + KeyValue2 as KeyValue, + ListRow2 as ListRow, + MinSizeGuard2 as MinSizeGuard, + Modal2 as Modal, + NotificationHost2 as NotificationHost, + Pane2 as Pane, + ProgressBar2 as ProgressBar, + Sidebar2 as Sidebar, + SignalBars2 as SignalBars, + TabbedPanel2 as TabbedPanel, + Tabs2 as Tabs, + Toggle2 as Toggle, + stepTabValue2 as stepTabValue, + usePane2 as usePane }; diff --git a/dist/config.js b/dist/config.js index 56da2f9..8385420 100644 --- a/dist/config.js +++ b/dist/config.js @@ -1,17 +1,17 @@ // @bun import { - COLOR_KEYS, - mergeColors, - mergeConfig, - normalizeColor, - normalizeColors, - resolveBorderStyle -} from "./chunk-hcq62p48.js"; + COLOR_KEYS2, + OPENTUI_BORDER_STYLES2, + ThemeConfigSchema2, + layerConfigs2, + resolveConfig2, + normalizeColor2 +} from "./chunk-njvj322f.js"; export { - resolveBorderStyle, - normalizeColors, - normalizeColor, - mergeConfig, - mergeColors, - COLOR_KEYS + COLOR_KEYS2 as COLOR_KEYS, + OPENTUI_BORDER_STYLES2 as OPENTUI_BORDER_STYLES, + ThemeConfigSchema2 as ThemeConfigSchema, + layerConfigs2 as layerConfigs, + normalizeColor2 as normalizeColor, + resolveConfig2 as resolveConfig }; diff --git a/dist/context/focus.js b/dist/context/focus.js new file mode 100644 index 0000000..54bad7d --- /dev/null +++ b/dist/context/focus.js @@ -0,0 +1,9 @@ +// @bun +import { + isInside2, + useFocusWithin2 +} from "../chunk-59dzyjgd.js"; +export { + isInside2 as isInside, + useFocusWithin2 as useFocusWithin +}; diff --git a/dist/context/help.js b/dist/context/help.js index 72c67e5..ff583fc 100644 --- a/dist/context/help.js +++ b/dist/context/help.js @@ -1,9 +1,9 @@ // @bun import { - helpOpen, - toggleHelp -} from "../chunk-cyvpvpws.js"; + helpOpen2, + toggleHelp2 +} from "../chunk-ee2qaswx.js"; export { - toggleHelp, - helpOpen + helpOpen2 as helpOpen, + toggleHelp2 as toggleHelp }; diff --git a/dist/context/helper.js b/dist/context/helper.js index fe134c1..c0c1034 100644 --- a/dist/context/helper.js +++ b/dist/context/helper.js @@ -1,7 +1,7 @@ // @bun import { - createSimpleContext -} from "../chunk-2px9e43p.js"; + createSimpleContext2 +} from "../chunk-jza406qg.js"; export { - createSimpleContext + createSimpleContext2 as createSimpleContext }; diff --git a/dist/context/index.js b/dist/context/index.js index 51fb61b..8f9d6ef 100644 --- a/dist/context/index.js +++ b/dist/context/index.js @@ -1,21 +1,27 @@ // @bun import { - createSimpleContext -} from "../chunk-2px9e43p.js"; + createSimpleContext2 +} from "../chunk-jza406qg.js"; import { - helpOpen, - toggleHelp -} from "../chunk-cyvpvpws.js"; + notifications2, + notify2, + dismiss2 +} from "../chunk-6ggk5fg7.js"; import { - dismiss, - notifications, - notify -} from "../chunk-y6txxzxk.js"; + helpOpen2, + toggleHelp2 +} from "../chunk-ee2qaswx.js"; +import { + isInside2, + useFocusWithin2 +} from "../chunk-59dzyjgd.js"; export { - toggleHelp, - notify, - notifications, - helpOpen, - dismiss, - createSimpleContext + createSimpleContext2 as createSimpleContext, + dismiss2 as dismiss, + helpOpen2 as helpOpen, + isInside2 as isInside, + notifications2 as notifications, + notify2 as notify, + toggleHelp2 as toggleHelp, + useFocusWithin2 as useFocusWithin }; diff --git a/dist/context/notifications.js b/dist/context/notifications.js index a3b0ae5..23e43bf 100644 --- a/dist/context/notifications.js +++ b/dist/context/notifications.js @@ -1,11 +1,11 @@ // @bun import { - dismiss, - notifications, - notify -} from "../chunk-y6txxzxk.js"; + notifications2, + notify2, + dismiss2 +} from "../chunk-6ggk5fg7.js"; export { - notify, - notifications, - dismiss + dismiss2 as dismiss, + notifications2 as notifications, + notify2 as notify }; diff --git a/dist/index.js b/dist/index.js index 9852f97..5479e90 100644 --- a/dist/index.js +++ b/dist/index.js @@ -1,15 +1,23 @@ // @bun import { - presets, - theme -} from "./chunk-x7m82z3z.js"; + theme2, + presets2, + configureTheme2, + icon2 +} from "./chunk-p6jvscj3.js"; +import"./chunk-yyg967q8.js"; import { - configPath -} from "./chunk-7f8jagy5.js"; -import"./chunk-hcq62p48.js"; -import"./chunk-cnhhssmz.js"; + ThemeConfigSchema2 +} from "./chunk-njvj322f.js"; +import"./chunk-6ggk5fg7.js"; +import { + configPath2 +} from "./chunk-xykm10y9.js"; export { - theme, - presets, - configPath + ThemeConfigSchema2 as ThemeConfigSchema, + configPath2 as configPath, + configureTheme2 as configureTheme, + icon2 as icon, + presets2 as presets, + theme2 as theme }; diff --git a/dist/keymap/provider.js b/dist/keymap/provider.js index a03d347..1d4b8cd 100644 --- a/dist/keymap/provider.js +++ b/dist/keymap/provider.js @@ -19,9 +19,9 @@ function KeymapProvider(props) { }); } export { - useKeymapSelector, - useKeymap, - useBindings, + KeymapProvider, reactiveMatcherFromSignal, - KeymapProvider + useBindings, + useKeymap, + useKeymapSelector }; diff --git a/dist/presets.js b/dist/presets.js index f1f5f9d..adb2a2e 100644 --- a/dist/presets.js +++ b/dist/presets.js @@ -1,7 +1,7 @@ // @bun import { - buildPresets -} from "./chunk-cnhhssmz.js"; + buildPresets2 +} from "./chunk-yyg967q8.js"; export { - buildPresets + buildPresets2 as buildPresets }; diff --git a/dist/project-config.js b/dist/project-config.js index 1ac3bdc..99ffd3f 100644 --- a/dist/project-config.js +++ b/dist/project-config.js @@ -1,7 +1,7 @@ // @bun import { - notify -} from "./chunk-y6txxzxk.js"; + notify2 +} from "./chunk-6ggk5fg7.js"; // src/project-config.ts import { existsSync, readFileSync } from "fs"; @@ -19,7 +19,7 @@ function readYaml(path) { function warn(projectName, path, message) { const text = `${path}: ${message}`; console.error(`[${projectName} config] ${text}`); - notify(text, { kind: "warning", duration: 0 }); + notify2(text, { kind: "warning", duration: 0 }); } function loadProjectConfig(options) { const { projectName, defaultConfigPath, defaultSchema, userSchema } = options; @@ -54,6 +54,47 @@ ${z.prettifyError(defaultsResult.error)}`); })(); return { defaults: defaultsResult.data, user }; } +function isPlainObject(value) { + return typeof value === "object" && value !== null && !Array.isArray(value); +} +function deepMerge(base, over) { + if (!isPlainObject(base) || !isPlainObject(over)) + return over === undefined ? base : over; + const out = { ...base }; + for (const [key, value] of Object.entries(over)) + out[key] = deepMerge(base[key], value); + return out; +} +function loadMergedProjectConfig(options) { + const { projectName, defaultConfigPath, schema } = options; + let rawDefaults; + try { + rawDefaults = readYaml(defaultConfigPath); + } catch (error) { + throw new Error(`Failed to read ${defaultConfigPath}: ${error instanceof Error ? error.message : error}`); + } + const defaults = schema.safeParse(rawDefaults); + if (!defaults.success) { + throw new Error(`${defaultConfigPath} is invalid: +${z.prettifyError(defaults.error)}`); + } + const path = userConfigPath(projectName); + if (!existsSync(path)) + return defaults.data; + let rawUser; + try { + rawUser = readYaml(path); + } catch (error) { + warn(projectName, path, error instanceof Error ? error.message : String(error)); + return defaults.data; + } + const merged = schema.safeParse(deepMerge(rawDefaults, rawUser ?? {})); + if (!merged.success) { + warn(projectName, path, z.prettifyError(merged.error)); + return defaults.data; + } + return merged.data; +} function keybindsSchema(names, required) { const shape = {}; for (const name of names) { @@ -69,7 +110,8 @@ function mergeKeybinds(names, defaults, user) { return merged; } export { - mergeKeybinds, + keybindsSchema, + loadMergedProjectConfig, loadProjectConfig, - keybindsSchema + mergeKeybinds }; diff --git a/dist/solid.js b/dist/solid.js index 853f0d8..d55a414 100644 --- a/dist/solid.js +++ b/dist/solid.js @@ -1,11 +1,12 @@ // @bun +import"./chunk-njvj322f.js"; +import"./chunk-6ggk5fg7.js"; +import"./chunk-yyg967q8.js"; +import"./chunk-xykm10y9.js"; import { - presets, - theme -} from "./chunk-x7m82z3z.js"; -import"./chunk-7f8jagy5.js"; -import"./chunk-hcq62p48.js"; -import"./chunk-cnhhssmz.js"; + theme2, + presets2 +} from "./chunk-p6jvscj3.js"; // src/solid.ts import { extend } from "@opentui/solid"; @@ -23,23 +24,25 @@ function withThemeDefaults(Ctor, defaults, after) { class Themed extends Ctor { constructor(...args) { super(...args); - Object.assign(this, defaults); + Object.assign(this, defaults()); after?.(this); } } return Themed; } -var { borderStyle, borderColor, focusedBorderColor } = presets.box; -var boxDefaults = { borderStyle, borderColor, focusedBorderColor }; +var boxDefaults = () => { + const { borderStyle, borderColor, focusedBorderColor } = presets2.box; + return { borderStyle, borderColor, focusedBorderColor }; +}; extend({ box: withThemeDefaults(BoxRenderable, boxDefaults, (instance) => { instance.border = false; }), - select: withThemeDefaults(SelectRenderable, presets.select), - tab_select: withThemeDefaults(TabSelectRenderable, presets.tabSelect), - input: withThemeDefaults(InputRenderable, presets.input), - textarea: withThemeDefaults(TextareaRenderable, presets.textarea), - slider: withThemeDefaults(SliderRenderable, presets.slider), - text: withThemeDefaults(TextRenderable, { fg: theme.text }), - ascii_font: withThemeDefaults(ASCIIFontRenderable, { color: theme.primary }) + select: withThemeDefaults(SelectRenderable, () => presets2.select), + tab_select: withThemeDefaults(TabSelectRenderable, () => presets2.tabSelect), + input: withThemeDefaults(InputRenderable, () => presets2.input), + textarea: withThemeDefaults(TextareaRenderable, () => presets2.textarea), + slider: withThemeDefaults(SliderRenderable, () => presets2.slider), + text: withThemeDefaults(TextRenderable, () => ({ fg: theme2.text })), + ascii_font: withThemeDefaults(ASCIIFontRenderable, () => ({ color: theme2.primary })) }); diff --git a/dist/yaml.js b/dist/yaml.js index dc026e1..a1f2190 100644 --- a/dist/yaml.js +++ b/dist/yaml.js @@ -1,9 +1,7 @@ // @bun import { - configPath, - readYamlFile -} from "./chunk-7f8jagy5.js"; + configPath2 +} from "./chunk-xykm10y9.js"; export { - readYamlFile, - configPath + configPath2 as configPath }; diff --git a/package.json b/package.json index ec30e6e..cfcb85d 100644 --- a/package.json +++ b/package.json @@ -12,7 +12,8 @@ "./keymap": { "types": "./src/keymap/provider.tsx", "default": "./dist/keymap/provider.js" }, "./components": { "types": "./src/components/index.ts", "default": "./dist/components/index.js" }, "./components/spinner": { "types": "./src/components/Spinner.tsx", "default": "./dist/components/Spinner.js" }, - "./components/help": { "types": "./src/components/help.ts", "default": "./dist/components/help.js" } + "./components/help": { "types": "./src/components/help.ts", "default": "./dist/components/help.js" }, + "./components/section-header": { "types": "./src/components/SectionHeader.tsx", "default": "./dist/components/SectionHeader.js" } }, "private": true, "files": ["dist", "src"], diff --git a/src/components/HelpModal.tsx b/src/components/HelpModal.tsx index 2884f64..03fa0e9 100644 --- a/src/components/HelpModal.tsx +++ b/src/components/HelpModal.tsx @@ -1,6 +1,7 @@ -import { type ColorInput, TextAttributes } from "@opentui/core"; +import { type ColorInput, type Renderable, TextAttributes } from "@opentui/core"; import { formatCommandBindings } from "@opentui/keymap/extras"; import { useKeymapSelector } from "@opentui/keymap/solid"; +import { createSignal } from "solid-js"; import { helpOpen, toggleHelp } from "../context/help.ts"; import { Modal } from "./Modal.tsx"; @@ -11,6 +12,8 @@ export interface HelpModalProps { backgroundColor?: ColorInput; backdropColor?: ColorInput; width?: number; + /** See ModalProps.dismissKey. */ + dismissKey?: string | false; } interface HelpEntry { @@ -20,8 +23,13 @@ interface HelpEntry { } export function HelpModal(props: HelpModalProps = {}) { + // The modal takes focus when it opens, which would make its own "close" + // the only active command. List what was active where focus was *before* + // it opened instead. + const [scope, setScope] = createSignal(null); + const entries = useKeymapSelector((keymap): HelpEntry[] => - keymap.getCommandEntries({ visibility: "active" }).map((entry) => ({ + keymap.getCommandEntries({ visibility: "active", focused: scope() }).map((entry) => ({ command: entry.command.name, keys: formatCommandBindings(entry.bindings, { keyNameAliases: KEY_DISPLAY }) ?? "", label: typeof entry.command.desc === "string" ? entry.command.desc : entry.command.name, @@ -32,6 +40,8 @@ export function HelpModal(props: HelpModalProps = {}) { setScope(() => previous)} + dismissKey={props.dismissKey} accentColor={props.accentColor} backgroundColor={props.backgroundColor} backdropColor={props.backdropColor} diff --git a/src/components/KeyValue.tsx b/src/components/KeyValue.tsx new file mode 100644 index 0000000..9110e0c --- /dev/null +++ b/src/components/KeyValue.tsx @@ -0,0 +1,23 @@ +import type { ColorInput } from "@opentui/core"; +import { Show, type JSX } from "solid-js"; +import { theme } from "../index.ts"; + +export interface KeyValueProps { + label: string; + /** Plain value; ignored when children are given. */ + value?: string | number; + valueColor?: ColorInput; + children?: JSX.Element; +} + +/** A "Label ........ value" line, as used in details panels and modals. */ +export function KeyValue(props: KeyValueProps) { + return ( + + {props.label} + {props.value ?? ""}}> + {props.children} + + + ); +} diff --git a/src/components/ListRow.tsx b/src/components/ListRow.tsx new file mode 100644 index 0000000..befe903 --- /dev/null +++ b/src/components/ListRow.tsx @@ -0,0 +1,49 @@ +import { type ColorInput, TextAttributes } from "@opentui/core"; +import { Show, type JSX } from "solid-js"; +import { presets, theme } from "../index.ts"; + +/** Returns the selected-row text color when the row is selected, `fallback` otherwise. */ +export type RowTone = (fallback?: ColorInput) => ColorInput | undefined; + +export interface ListRowProps { + id?: string; + label: string; + selected: boolean; + bold?: boolean; + onClick?: () => void; + /** Right-aligned content; use `tone` for its colors so it follows the selection. */ + right?: (tone: RowTone) => JSX.Element; + /** Extra lines under the main one. */ + below?: (tone: RowTone) => JSX.Element; +} + +/** One row of a keyboard-navigable list: truncated label on the left, details on the right. */ +export function ListRow(props: ListRowProps) { + const tone: RowTone = (fallback) => (props.selected ? presets.select.selectedTextColor : fallback); + + return ( + props.onClick?.() : undefined} + > + + + + {props.label} + + + + + {props.right?.(tone)} + + + + {props.below?.(tone)} + + ); +} diff --git a/src/components/Modal.tsx b/src/components/Modal.tsx index 6ad0f28..71ef32e 100644 --- a/src/components/Modal.tsx +++ b/src/components/Modal.tsx @@ -1,11 +1,26 @@ -import { type ColorInput, type MouseEvent, RGBA } from "@opentui/core"; -import { Portal, useTerminalDimensions } from "@opentui/solid"; -import { Show, type ParentProps } from "solid-js"; +import { type BoxRenderable, type ColorInput, type KeyEvent, type MouseEvent, type Renderable, RGBA } from "@opentui/core"; +import type { Binding, Command } from "@opentui/keymap"; +import { useBindings } from "@opentui/keymap/solid"; +import { Portal, useRenderer, useTerminalDimensions } from "@opentui/solid"; +import { createSignal, onCleanup, onMount, Show, type ParentProps } from "solid-js"; import { theme } from "../index.ts"; +export type ModalCommand = Command; +export type ModalBinding = Binding; + export interface ModalProps extends ParentProps { open: boolean; onDismiss?: () => void; + /** + * Key that calls onDismiss while the modal has focus (default "escape"). + * `false` disables it. Needs a KeymapProvider unless disabled. + */ + dismissKey?: string | false; + /** Extra keymap commands/bindings, active only while the modal has focus. */ + commands?: ModalCommand[]; + bindings?: ModalBinding[]; + /** Called on open with whatever had focus before the modal took it. */ + onOpen?: (previousFocus: Renderable | null) => void; accentColor?: ColorInput; backgroundColor?: ColorInput; backdropColor?: ColorInput; @@ -15,57 +30,96 @@ export interface ModalProps extends ParentProps { } export function Modal(props: ModalProps) { + return ( + + + + + + ); +} + +// Mounted only while open: takes native focus on mount and hands it back to +// whatever had it on unmount, so keymap layers scoped to the page underneath +// go quiet while the modal is up and come back on their own afterwards. +function ModalPanel(props: ModalProps) { + const renderer = useRenderer(); const dimensions = useTerminalDimensions(); + const [panel, setPanel] = createSignal(); + const screenCap = () => Math.max(5, dimensions().height - 4); const maxPanelHeight = () => Math.min(props.maxHeight ?? screenCap(), screenCap()); const maxContentHeight = () => Math.max(1, maxPanelHeight() - 4); const maxPanelWidth = () => Math.max(10, dimensions().width - 4); const panelWidth = () => Math.min(props.width ?? 50, maxPanelWidth()); + let previousFocus: Renderable | null = null; + onMount(() => { + previousFocus = renderer.currentFocusedRenderable; + props.onOpen?.(previousFocus); + panel()?.focus(); + }); + onCleanup(() => { + if (previousFocus && !previousFocus.isDestroyed) previousFocus.focus(); + }); + + const dismissKey = props.dismissKey ?? "escape"; + if (dismissKey !== false || props.commands || props.bindings) { + useBindings(() => ({ + target: panel, + commands: [ + ...(dismissKey !== false + ? [{ name: "modal_dismiss", desc: "close", shortHelp: true, run: () => props.onDismiss?.() }] + : []), + ...(props.commands ?? []), + ], + bindings: [...(dismissKey !== false ? [{ key: dismissKey, cmd: "modal_dismiss" }] : []), ...(props.bindings ?? [])], + })); + } + return ( - - - + event.stopPropagation() : undefined} + > + + {props.children} + + } > - event.stopPropagation() : undefined} - > - - {props.children} - - } - > - - {props.children} - - - - - - + + {props.children} + + + + ); } diff --git a/src/components/Pane.tsx b/src/components/Pane.tsx new file mode 100644 index 0000000..fb1af67 --- /dev/null +++ b/src/components/Pane.tsx @@ -0,0 +1,48 @@ +import type { BoxRenderable } from "@opentui/core"; +import type { BoxProps } from "@opentui/solid"; +import { type Accessor, createContext, createSignal, splitProps, useContext } from "solid-js"; +import { useFocusWithin } from "../context/focus.ts"; + +export interface PaneHandle { + /** The pane's root renderable — use it as a keymap layer `target`. */ + target: Accessor; + /** True while native focus is anywhere inside the pane. */ + focused: Accessor; + focus(): void; +} + +const PaneContext = createContext(); + +export interface PaneProps extends Omit { + /** Receives the pane's handle, e.g. to focus it or target it from outside. */ + handle?: (handle: PaneHandle) => void; +} + +/** + * A focus region. Wrap each independently focusable area (sidebar, content, + * …) in a Pane; anything inside can call usePane() to scope keymap layers to + * it (`useBindings(() => ({ target: pane.target, … }))`) and to style itself + * from `pane.focused()`. Pass `focusable` when the pane itself should be the + * focus target (rather than e.g. a