@kitlangton/knobs 0.2.0 → 0.3.0
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- package/README.md +135 -17
- package/dist/dev/{chunk-gezhc24g.js → chunk-7xgkerd2.js} +14 -5
- package/dist/dev/{chunk-5cr85vv6.js → chunk-jx1ktap3.js} +7843 -7933
- package/dist/dev/{chunk-693jd1gj.js → chunk-pmkvb9ep.js} +1544 -160
- package/dist/dev/{chunk-4km87zfx.js → chunk-v8ssbcbk.js} +18 -7
- package/dist/dev/index.js +187 -31
- package/dist/index.js +197 -33
- package/dist/panel.js +20260 -18462
- package/dist/types/core/keys.d.ts +2 -0
- package/dist/types/core/remote.d.ts +2 -0
- package/dist/types/core/schema.d.ts +5 -0
- package/dist/types/core/store.d.ts +29 -2
- package/dist/types/core/unlock.d.ts +77 -0
- package/dist/types/index.d.ts +1 -0
- package/dist/types/panel/attach.d.ts +2 -0
- package/dist/types/panel/crumbs.d.ts +19 -0
- package/dist/types/panel/editors.d.ts +9 -0
- package/dist/types/panel/feel.d.ts +103 -0
- package/dist/types/panel/give.d.ts +34 -1
- package/dist/types/panel/gpu/color.d.ts +4 -4
- package/dist/types/panel/gpu/renderer.d.ts +32 -0
- package/dist/types/panel/gpu/shader.wgsl.d.ts +1 -1
- package/dist/types/panel/index.d.ts +2 -1
- package/dist/types/panel/inspector.d.ts +1 -1
- package/dist/types/panel/lens.d.ts +113 -0
- package/dist/types/panel/motion.d.ts +2 -0
- package/dist/types/panel/page-hints.d.ts +2 -1
- package/dist/types/panel/prefs.d.ts +2 -2
- package/dist/types/panel/presence.d.ts +20 -0
- package/dist/types/panel/scope.d.ts +29 -0
- package/dist/types/panel/slider.d.ts +21 -4
- package/dist/types/panel/tab-transition.d.ts +15 -0
- package/dist/types/panel/tabs.d.ts +1 -1
- package/dist/types/panel/toggle.d.ts +27 -0
- package/dist/types/ui/look.d.ts +1 -1
- package/dist/types/ui/scrollbar.d.ts +12 -0
- package/dist/types/ui/split-model.d.ts +4 -3
- package/dist/types/ui/split.d.ts +8 -6
- package/dist/ui-react.js +232 -132
- package/dist/ui-solid.js +232 -132
- package/dist/ui.js +285 -174
- package/package.json +1 -1
package/dist/ui.js
CHANGED
|
@@ -276,7 +276,7 @@ var open = springEasing(2 * Math.PI / 0.22, 1);
|
|
|
276
276
|
var activityCss = `
|
|
277
277
|
:where(.knobs-activity,.knobs-activity *){box-sizing:border-box}
|
|
278
278
|
:where(.knobs-activity){color-scheme:dark}
|
|
279
|
-
.knobs-ui.knobs-activity{position:relative;display:block;height:100%;overflow:auto;overflow-anchor:none;outline:none;scrollbar-width:
|
|
279
|
+
.knobs-ui.knobs-activity{position:relative;display:block;height:100%;overflow:auto;overflow-anchor:none;outline:none;scrollbar-width:none;overscroll-behavior:contain;user-select:none;-webkit-user-select:none;
|
|
280
280
|
font:var(--ku-font-weight) var(--ku-font-size)/1.35 var(--ku-font);color:var(--ku-text);text-align:left;letter-spacing:normal;-webkit-font-smoothing:antialiased;
|
|
281
281
|
--ka-gutter:var(--k-activity-gutter,28px);--ka-row:var(--k-activity-row,var(--ku-row));--ka-row-child:var(--k-activity-row-child,calc(var(--ka-row) - 6px));
|
|
282
282
|
--ka-line:var(--k-activity-line,var(--ku-line-hi));--ka-select:var(--k-activity-select,var(--ku-wash-hi));--ka-hover:var(--k-activity-hover,var(--ku-wash));
|
|
@@ -627,6 +627,160 @@ var readoutCss = `
|
|
|
627
627
|
@media(prefers-reduced-motion:reduce){.knobs-rd :where(*){transition:none!important}}
|
|
628
628
|
`;
|
|
629
629
|
|
|
630
|
+
// src/core/keys.ts
|
|
631
|
+
var MODS = ["Ctrl", "Alt", "Shift", "Meta"];
|
|
632
|
+
var ALIASES = {
|
|
633
|
+
ctrl: "Ctrl",
|
|
634
|
+
control: "Ctrl",
|
|
635
|
+
"⌃": "Ctrl",
|
|
636
|
+
alt: "Alt",
|
|
637
|
+
option: "Alt",
|
|
638
|
+
opt: "Alt",
|
|
639
|
+
"⌥": "Alt",
|
|
640
|
+
shift: "Shift",
|
|
641
|
+
"⇧": "Shift",
|
|
642
|
+
meta: "Meta",
|
|
643
|
+
cmd: "Meta",
|
|
644
|
+
command: "Meta",
|
|
645
|
+
"⌘": "Meta",
|
|
646
|
+
mod: "Mod"
|
|
647
|
+
};
|
|
648
|
+
var NAMED = {
|
|
649
|
+
" ": "Space",
|
|
650
|
+
space: "Space",
|
|
651
|
+
spacebar: "Space",
|
|
652
|
+
esc: "Escape",
|
|
653
|
+
escape: "Escape",
|
|
654
|
+
enter: "Enter",
|
|
655
|
+
return: "Enter",
|
|
656
|
+
tab: "Tab",
|
|
657
|
+
backspace: "Backspace",
|
|
658
|
+
delete: "Delete",
|
|
659
|
+
del: "Delete",
|
|
660
|
+
up: "ArrowUp",
|
|
661
|
+
down: "ArrowDown",
|
|
662
|
+
left: "ArrowLeft",
|
|
663
|
+
right: "ArrowRight",
|
|
664
|
+
arrowup: "ArrowUp",
|
|
665
|
+
arrowdown: "ArrowDown",
|
|
666
|
+
arrowleft: "ArrowLeft",
|
|
667
|
+
arrowright: "ArrowRight",
|
|
668
|
+
home: "Home",
|
|
669
|
+
end: "End",
|
|
670
|
+
pageup: "PageUp",
|
|
671
|
+
pagedown: "PageDown"
|
|
672
|
+
};
|
|
673
|
+
var isApple = () => typeof navigator !== "undefined" && /mac|iphone|ipad|ipod/i.test(navigator.userAgentData?.platform ?? navigator.platform ?? "");
|
|
674
|
+
var keyName = (raw) => {
|
|
675
|
+
if (!raw)
|
|
676
|
+
return "";
|
|
677
|
+
const named = NAMED[raw.toLowerCase()];
|
|
678
|
+
if (named)
|
|
679
|
+
return named;
|
|
680
|
+
if (raw.length === 1)
|
|
681
|
+
return raw.toUpperCase();
|
|
682
|
+
if (/^f\d{1,2}$/i.test(raw))
|
|
683
|
+
return raw.toUpperCase();
|
|
684
|
+
return raw.charAt(0).toUpperCase() + raw.slice(1);
|
|
685
|
+
};
|
|
686
|
+
function normalizeCombo(combo) {
|
|
687
|
+
const trimmed = combo.trim();
|
|
688
|
+
if (!trimmed)
|
|
689
|
+
return "";
|
|
690
|
+
const parts = trimmed === "+" ? ["+"] : trimmed.replace(/\+\+$/, "+plus").split("+");
|
|
691
|
+
const mods = new Set;
|
|
692
|
+
let key = "";
|
|
693
|
+
for (const part of parts) {
|
|
694
|
+
const alias = ALIASES[part.trim().toLowerCase()] ?? ALIASES[part.trim()];
|
|
695
|
+
if (alias === "Mod")
|
|
696
|
+
mods.add(isApple() ? "Meta" : "Ctrl");
|
|
697
|
+
else if (alias)
|
|
698
|
+
mods.add(alias);
|
|
699
|
+
else
|
|
700
|
+
key = part === "plus" ? "+" : keyName(part.trim() || part);
|
|
701
|
+
}
|
|
702
|
+
if (!key)
|
|
703
|
+
return "";
|
|
704
|
+
return [...MODS.filter((m) => mods.has(m)), key].join("+");
|
|
705
|
+
}
|
|
706
|
+
var layout = null;
|
|
707
|
+
var layoutAsked = false;
|
|
708
|
+
function askLayout() {
|
|
709
|
+
if (layoutAsked)
|
|
710
|
+
return;
|
|
711
|
+
layoutAsked = true;
|
|
712
|
+
const keyboard = globalThis.navigator?.keyboard;
|
|
713
|
+
keyboard?.getLayoutMap?.().then((map) => {
|
|
714
|
+
layout = map;
|
|
715
|
+
}).catch(() => {});
|
|
716
|
+
}
|
|
717
|
+
function letterOf(event) {
|
|
718
|
+
askLayout();
|
|
719
|
+
const code = event.code ?? "";
|
|
720
|
+
if (/^[a-z]$/i.test(event.key) && !event.altKey)
|
|
721
|
+
return event.key.toUpperCase();
|
|
722
|
+
const mapped = layout?.get(code);
|
|
723
|
+
if (mapped && /^[a-z]$/i.test(mapped))
|
|
724
|
+
return mapped.toUpperCase();
|
|
725
|
+
return /^Key[A-Z]$/.test(code) ? code.slice(3) : "";
|
|
726
|
+
}
|
|
727
|
+
function comboFromEvent(event) {
|
|
728
|
+
if (["Shift", "Alt", "Meta", "Control", "CapsLock", "Fn", "OS"].includes(event.key))
|
|
729
|
+
return "";
|
|
730
|
+
const code = event.code ?? "";
|
|
731
|
+
const letter = letterOf(event);
|
|
732
|
+
const key = letter ? letter : /^Digit\d$/.test(code) ? code.slice(5) : code === "Space" ? "Space" : keyName(event.key);
|
|
733
|
+
return [
|
|
734
|
+
event.ctrlKey ? "Ctrl" : "",
|
|
735
|
+
event.altKey ? "Alt" : "",
|
|
736
|
+
event.shiftKey ? "Shift" : "",
|
|
737
|
+
event.metaKey ? "Meta" : "",
|
|
738
|
+
key
|
|
739
|
+
].filter(Boolean).join("+");
|
|
740
|
+
}
|
|
741
|
+
function matchesCombo(combo, event) {
|
|
742
|
+
const want = normalizeCombo(combo);
|
|
743
|
+
return want !== "" && want === comboFromEvent(event);
|
|
744
|
+
}
|
|
745
|
+
var GLYPHS = { Ctrl: "⌃", Alt: "⌥", Shift: "⇧", Meta: "⌘" };
|
|
746
|
+
var WORDS = { Ctrl: "Ctrl", Alt: "Alt", Shift: "Shift", Meta: "Meta" };
|
|
747
|
+
var KEY_GLYPHS = {
|
|
748
|
+
ArrowUp: "↑",
|
|
749
|
+
ArrowDown: "↓",
|
|
750
|
+
ArrowLeft: "←",
|
|
751
|
+
ArrowRight: "→",
|
|
752
|
+
Backspace: "⌫",
|
|
753
|
+
Delete: "⌦",
|
|
754
|
+
Enter: "↩",
|
|
755
|
+
Escape: "Esc",
|
|
756
|
+
Tab: "⇥",
|
|
757
|
+
PageUp: "PgUp",
|
|
758
|
+
PageDown: "PgDn"
|
|
759
|
+
};
|
|
760
|
+
function comboParts(combo, apple = isApple()) {
|
|
761
|
+
const norm = normalizeCombo(combo);
|
|
762
|
+
if (!norm)
|
|
763
|
+
return [];
|
|
764
|
+
const parts = norm === "+" ? ["+"] : norm.split("+");
|
|
765
|
+
if (norm.endsWith("++"))
|
|
766
|
+
parts.splice(-2, 2, "+");
|
|
767
|
+
const key = parts.pop();
|
|
768
|
+
const mods = parts;
|
|
769
|
+
const shown = KEY_GLYPHS[key] ?? key;
|
|
770
|
+
return apple ? [...mods.map((m) => GLYPHS[m]), shown] : [...mods.map((m) => WORDS[m]), shown];
|
|
771
|
+
}
|
|
772
|
+
function isTypingTarget(target) {
|
|
773
|
+
const el = target;
|
|
774
|
+
if (!el || typeof el.tagName !== "string")
|
|
775
|
+
return false;
|
|
776
|
+
const tag = el.tagName;
|
|
777
|
+
if (tag === "SELECT" || el.isContentEditable)
|
|
778
|
+
return true;
|
|
779
|
+
if (tag === "TEXTAREA")
|
|
780
|
+
return !el.readOnly;
|
|
781
|
+
return tag === "INPUT" && !el.readOnly && !["range", "checkbox", "radio", "button", "submit", "reset", "color"].includes(el.type);
|
|
782
|
+
}
|
|
783
|
+
|
|
630
784
|
// src/ui/look.ts
|
|
631
785
|
var ease = springEasing(26, 1);
|
|
632
786
|
var TOKENS = {
|
|
@@ -744,6 +898,17 @@ var css = `
|
|
|
744
898
|
}
|
|
745
899
|
@supports not (animation-timeline:scroll()){.knobs-scroll-fade-x{text-overflow:ellipsis}}
|
|
746
900
|
|
|
901
|
+
/* Overlay scrollbars (trees, activity rails): a thin thumb over the content, so the rows never
|
|
902
|
+
give up width to a scrollbar as they start or stop overflowing. It shows while the content
|
|
903
|
+
scrolls or the pointer is over it. */
|
|
904
|
+
:is(.knobs-tree,.knobs-activity)::-webkit-scrollbar{display:none}
|
|
905
|
+
.knobs-scrollbar{position:sticky;top:0;z-index:3;height:0;pointer-events:none}
|
|
906
|
+
.knobs-scrollbar[hidden]{display:none}
|
|
907
|
+
.knobs-scrollbar-thumb{position:absolute;top:0;right:2px;width:5px;border-radius:3px;background:color-mix(in srgb,var(--ku-text) 30%,transparent);opacity:0;
|
|
908
|
+
transition:opacity .3s ease-out,background .15s}
|
|
909
|
+
:hover>.knobs-scrollbar>.knobs-scrollbar-thumb,.knobs-scrollbar:is([data-active],[data-dragging])>.knobs-scrollbar-thumb{opacity:1;pointer-events:auto;transition-duration:.12s,.15s}
|
|
910
|
+
.knobs-scrollbar-thumb:hover,.knobs-scrollbar[data-dragging]>.knobs-scrollbar-thumb{background:color-mix(in srgb,var(--ku-text) 48%,transparent)}
|
|
911
|
+
|
|
747
912
|
/* Split: panes along a row or column, hairline dividers with a wider grip. */
|
|
748
913
|
.knobs-split{position:relative;display:flex;width:100%;height:100%;min-width:0;min-height:0;overflow:hidden}
|
|
749
914
|
.knobs-split[data-direction="column"]{flex-direction:column}
|
|
@@ -780,7 +945,11 @@ var css = `
|
|
|
780
945
|
.knobs-split[data-direction="column"]>.knobs-pane[data-edge="start"]>.knobs-pane-rail{bottom:0}
|
|
781
946
|
.knobs-split[data-direction="column"]>.knobs-pane[data-edge="end"]>.knobs-pane-rail{top:0}
|
|
782
947
|
.knobs-pane[data-collapsed]>.knobs-pane-rail{pointer-events:auto}
|
|
783
|
-
|
|
948
|
+
/* Its hover wash fades, rather than going in one frame as a click opens the pane. */
|
|
949
|
+
.knobs-ui .knobs-pane-rail::before{content:"";position:absolute;inset:0;border-radius:inherit;background:var(--ku-wash);opacity:0;transition:opacity .15s;pointer-events:none}
|
|
950
|
+
.knobs-pane-rail>*{position:relative}
|
|
951
|
+
.knobs-ui .knobs-pane[data-collapsed]>.knobs-pane-rail:is(:hover,:focus-visible){color:var(--ku-text)}
|
|
952
|
+
.knobs-ui .knobs-pane[data-collapsed]>.knobs-pane-rail:is(:hover,:focus-visible)::before{opacity:1}
|
|
784
953
|
.knobs-pane-rail-label{white-space:nowrap;overflow:hidden;text-overflow:ellipsis}
|
|
785
954
|
.knobs-pane-chevron{display:flex;flex:none;width:11px;height:11px;writing-mode:horizontal-tb;color:var(--ku-dim)}
|
|
786
955
|
.knobs-pane-turn{display:flex;width:100%;height:100%;transform-origin:50% 50%}
|
|
@@ -817,7 +986,7 @@ var css = `
|
|
|
817
986
|
:root[data-knobs-resizing] :is(iframe,canvas:not(.knobs-gpu-canvas)){pointer-events:none}
|
|
818
987
|
|
|
819
988
|
/* Tree: one scroller, rows placed by transform, only those near the view in the DOM. */
|
|
820
|
-
.knobs-tree{position:relative;overflow:auto;height:100%;outline:none;scrollbar-width:
|
|
989
|
+
.knobs-tree{position:relative;overflow:auto;height:100%;outline:none;scrollbar-width:none;overscroll-behavior:contain;user-select:none;-webkit-user-select:none}
|
|
821
990
|
.knobs-tree-space{position:relative;width:100%;pointer-events:none}
|
|
822
991
|
.knobs-tree-row{position:absolute;left:var(--ku-row-x);right:var(--ku-row-x);top:0;display:flex;align-items:center;height:var(--ku-row);padding-right:calc(var(--ku-inset) - 4px);
|
|
823
992
|
color:var(--ku-text);white-space:nowrap;cursor:default;will-change:transform;contain:layout style}
|
|
@@ -1018,7 +1187,6 @@ var tune = (s, m) => {
|
|
|
1018
1187
|
s.zeta = m.zeta;
|
|
1019
1188
|
return s;
|
|
1020
1189
|
};
|
|
1021
|
-
var isTypingTarget = (t) => t instanceof HTMLElement && (t.isContentEditable || t instanceof HTMLSelectElement || t instanceof HTMLTextAreaElement || t instanceof HTMLInputElement && !t.readOnly && !["range", "checkbox", "radio", "button"].includes(t.type));
|
|
1022
1190
|
function notifyLayout(doc) {
|
|
1023
1191
|
doc.dispatchEvent(new Event("knobs-layout"));
|
|
1024
1192
|
}
|
|
@@ -1057,149 +1225,6 @@ var ICONS = {
|
|
|
1057
1225
|
lock: svg('<rect x="3.5" y="7" width="9" height="6.5" rx="1.2"/><path d="M5.5 7V5a2.5 2.5 0 0 1 5 0v2"/>'),
|
|
1058
1226
|
unlock: svg('<rect x="3.5" y="7" width="9" height="6.5" rx="1.2"/><path d="M5.5 7V5a2.5 2.5 0 0 1 4.8-1"/>')
|
|
1059
1227
|
};
|
|
1060
|
-
// src/core/keys.ts
|
|
1061
|
-
var MODS = ["Ctrl", "Alt", "Shift", "Meta"];
|
|
1062
|
-
var ALIASES = {
|
|
1063
|
-
ctrl: "Ctrl",
|
|
1064
|
-
control: "Ctrl",
|
|
1065
|
-
"⌃": "Ctrl",
|
|
1066
|
-
alt: "Alt",
|
|
1067
|
-
option: "Alt",
|
|
1068
|
-
opt: "Alt",
|
|
1069
|
-
"⌥": "Alt",
|
|
1070
|
-
shift: "Shift",
|
|
1071
|
-
"⇧": "Shift",
|
|
1072
|
-
meta: "Meta",
|
|
1073
|
-
cmd: "Meta",
|
|
1074
|
-
command: "Meta",
|
|
1075
|
-
"⌘": "Meta",
|
|
1076
|
-
mod: "Mod"
|
|
1077
|
-
};
|
|
1078
|
-
var NAMED = {
|
|
1079
|
-
" ": "Space",
|
|
1080
|
-
space: "Space",
|
|
1081
|
-
spacebar: "Space",
|
|
1082
|
-
esc: "Escape",
|
|
1083
|
-
escape: "Escape",
|
|
1084
|
-
enter: "Enter",
|
|
1085
|
-
return: "Enter",
|
|
1086
|
-
tab: "Tab",
|
|
1087
|
-
backspace: "Backspace",
|
|
1088
|
-
delete: "Delete",
|
|
1089
|
-
del: "Delete",
|
|
1090
|
-
up: "ArrowUp",
|
|
1091
|
-
down: "ArrowDown",
|
|
1092
|
-
left: "ArrowLeft",
|
|
1093
|
-
right: "ArrowRight",
|
|
1094
|
-
arrowup: "ArrowUp",
|
|
1095
|
-
arrowdown: "ArrowDown",
|
|
1096
|
-
arrowleft: "ArrowLeft",
|
|
1097
|
-
arrowright: "ArrowRight",
|
|
1098
|
-
home: "Home",
|
|
1099
|
-
end: "End",
|
|
1100
|
-
pageup: "PageUp",
|
|
1101
|
-
pagedown: "PageDown"
|
|
1102
|
-
};
|
|
1103
|
-
var isApple = () => typeof navigator !== "undefined" && /mac|iphone|ipad|ipod/i.test(navigator.userAgentData?.platform ?? navigator.platform ?? "");
|
|
1104
|
-
var keyName = (raw) => {
|
|
1105
|
-
if (!raw)
|
|
1106
|
-
return "";
|
|
1107
|
-
const named = NAMED[raw.toLowerCase()];
|
|
1108
|
-
if (named)
|
|
1109
|
-
return named;
|
|
1110
|
-
if (raw.length === 1)
|
|
1111
|
-
return raw.toUpperCase();
|
|
1112
|
-
if (/^f\d{1,2}$/i.test(raw))
|
|
1113
|
-
return raw.toUpperCase();
|
|
1114
|
-
return raw.charAt(0).toUpperCase() + raw.slice(1);
|
|
1115
|
-
};
|
|
1116
|
-
function normalizeCombo(combo) {
|
|
1117
|
-
const trimmed = combo.trim();
|
|
1118
|
-
if (!trimmed)
|
|
1119
|
-
return "";
|
|
1120
|
-
const parts = trimmed === "+" ? ["+"] : trimmed.replace(/\+\+$/, "+plus").split("+");
|
|
1121
|
-
const mods = new Set;
|
|
1122
|
-
let key = "";
|
|
1123
|
-
for (const part of parts) {
|
|
1124
|
-
const alias = ALIASES[part.trim().toLowerCase()] ?? ALIASES[part.trim()];
|
|
1125
|
-
if (alias === "Mod")
|
|
1126
|
-
mods.add(isApple() ? "Meta" : "Ctrl");
|
|
1127
|
-
else if (alias)
|
|
1128
|
-
mods.add(alias);
|
|
1129
|
-
else
|
|
1130
|
-
key = part === "plus" ? "+" : keyName(part.trim() || part);
|
|
1131
|
-
}
|
|
1132
|
-
if (!key)
|
|
1133
|
-
return "";
|
|
1134
|
-
return [...MODS.filter((m) => mods.has(m)), key].join("+");
|
|
1135
|
-
}
|
|
1136
|
-
var layout = null;
|
|
1137
|
-
var layoutAsked = false;
|
|
1138
|
-
function askLayout() {
|
|
1139
|
-
if (layoutAsked)
|
|
1140
|
-
return;
|
|
1141
|
-
layoutAsked = true;
|
|
1142
|
-
const keyboard = globalThis.navigator?.keyboard;
|
|
1143
|
-
keyboard?.getLayoutMap?.().then((map) => {
|
|
1144
|
-
layout = map;
|
|
1145
|
-
}).catch(() => {});
|
|
1146
|
-
}
|
|
1147
|
-
function letterOf(event) {
|
|
1148
|
-
askLayout();
|
|
1149
|
-
const code = event.code ?? "";
|
|
1150
|
-
if (/^[a-z]$/i.test(event.key) && !event.altKey)
|
|
1151
|
-
return event.key.toUpperCase();
|
|
1152
|
-
const mapped = layout?.get(code);
|
|
1153
|
-
if (mapped && /^[a-z]$/i.test(mapped))
|
|
1154
|
-
return mapped.toUpperCase();
|
|
1155
|
-
return /^Key[A-Z]$/.test(code) ? code.slice(3) : "";
|
|
1156
|
-
}
|
|
1157
|
-
function comboFromEvent(event) {
|
|
1158
|
-
if (["Shift", "Alt", "Meta", "Control", "CapsLock", "Fn", "OS"].includes(event.key))
|
|
1159
|
-
return "";
|
|
1160
|
-
const code = event.code ?? "";
|
|
1161
|
-
const letter = letterOf(event);
|
|
1162
|
-
const key = letter ? letter : /^Digit\d$/.test(code) ? code.slice(5) : code === "Space" ? "Space" : keyName(event.key);
|
|
1163
|
-
return [
|
|
1164
|
-
event.ctrlKey ? "Ctrl" : "",
|
|
1165
|
-
event.altKey ? "Alt" : "",
|
|
1166
|
-
event.shiftKey ? "Shift" : "",
|
|
1167
|
-
event.metaKey ? "Meta" : "",
|
|
1168
|
-
key
|
|
1169
|
-
].filter(Boolean).join("+");
|
|
1170
|
-
}
|
|
1171
|
-
function matchesCombo(combo, event) {
|
|
1172
|
-
const want = normalizeCombo(combo);
|
|
1173
|
-
return want !== "" && want === comboFromEvent(event);
|
|
1174
|
-
}
|
|
1175
|
-
var GLYPHS = { Ctrl: "⌃", Alt: "⌥", Shift: "⇧", Meta: "⌘" };
|
|
1176
|
-
var WORDS = { Ctrl: "Ctrl", Alt: "Alt", Shift: "Shift", Meta: "Meta" };
|
|
1177
|
-
var KEY_GLYPHS = {
|
|
1178
|
-
ArrowUp: "↑",
|
|
1179
|
-
ArrowDown: "↓",
|
|
1180
|
-
ArrowLeft: "←",
|
|
1181
|
-
ArrowRight: "→",
|
|
1182
|
-
Backspace: "⌫",
|
|
1183
|
-
Delete: "⌦",
|
|
1184
|
-
Enter: "↩",
|
|
1185
|
-
Escape: "Esc",
|
|
1186
|
-
Tab: "⇥",
|
|
1187
|
-
PageUp: "PgUp",
|
|
1188
|
-
PageDown: "PgDn"
|
|
1189
|
-
};
|
|
1190
|
-
function comboParts(combo, apple = isApple()) {
|
|
1191
|
-
const norm = normalizeCombo(combo);
|
|
1192
|
-
if (!norm)
|
|
1193
|
-
return [];
|
|
1194
|
-
const parts = norm === "+" ? ["+"] : norm.split("+");
|
|
1195
|
-
if (norm.endsWith("++"))
|
|
1196
|
-
parts.splice(-2, 2, "+");
|
|
1197
|
-
const key = parts.pop();
|
|
1198
|
-
const mods = parts;
|
|
1199
|
-
const shown = KEY_GLYPHS[key] ?? key;
|
|
1200
|
-
return apple ? [...mods.map((m) => GLYPHS[m]), shown] : [...mods.map((m) => WORDS[m]), shown];
|
|
1201
|
-
}
|
|
1202
|
-
|
|
1203
1228
|
// src/core/schema.ts
|
|
1204
1229
|
var READOUT_KINDS = new Set(["watch", "sparkline", "graph", "meter", "table", "log"]);
|
|
1205
1230
|
var isReadout = (field) => READOUT_KINDS.has(field.kind);
|
|
@@ -1760,15 +1785,7 @@ function claimsHintKey(doc, key) {
|
|
|
1760
1785
|
const holder = doc;
|
|
1761
1786
|
return key === PAGE_HINT_KEY && Boolean(holder[KEY]?.listening);
|
|
1762
1787
|
}
|
|
1763
|
-
var isTyping =
|
|
1764
|
-
const el = target;
|
|
1765
|
-
if (!el || typeof el.tagName !== "string")
|
|
1766
|
-
return false;
|
|
1767
|
-
const tag = el.tagName;
|
|
1768
|
-
if (tag === "TEXTAREA" || tag === "SELECT" || el.isContentEditable)
|
|
1769
|
-
return true;
|
|
1770
|
-
return tag === "INPUT" && !["range", "checkbox", "radio", "button", "submit", "reset", "color"].includes(el.type);
|
|
1771
|
-
};
|
|
1788
|
+
var isTyping = isTypingTarget;
|
|
1772
1789
|
var PRESSABLE = "button,a[href],summary,[role=button],[role=tab],[role=radio],[role=switch],[role=checkbox],[role=menuitem],[role=option]";
|
|
1773
1790
|
function activateElement(el) {
|
|
1774
1791
|
const pressable = el.matches(PRESSABLE) || el.tabIndex < 0 && !el.matches("input,select,textarea");
|
|
@@ -3353,7 +3370,18 @@ function parseCssColor(raw, fallback = [1, 1, 1, 1]) {
|
|
|
3353
3370
|
parseInt(full.slice(4, 6), 16) / 255,
|
|
3354
3371
|
full.length === 8 ? parseInt(full.slice(6, 8), 16) / 255 : 1
|
|
3355
3372
|
];
|
|
3356
|
-
} else {
|
|
3373
|
+
} else if (s.startsWith("rgb")) {
|
|
3374
|
+
const nums = s.match(/[\d.]+/g)?.map(Number);
|
|
3375
|
+
if (nums && nums.length >= 3) {
|
|
3376
|
+
out = [
|
|
3377
|
+
Math.min(1, Math.max(0, nums[0] / 255)),
|
|
3378
|
+
Math.min(1, Math.max(0, nums[1] / 255)),
|
|
3379
|
+
Math.min(1, Math.max(0, nums[2] / 255)),
|
|
3380
|
+
nums.length >= 4 ? Math.min(1, Math.max(0, nums[3])) : 1
|
|
3381
|
+
];
|
|
3382
|
+
}
|
|
3383
|
+
}
|
|
3384
|
+
if (!out) {
|
|
3357
3385
|
const ctx = probeCtx();
|
|
3358
3386
|
if (ctx) {
|
|
3359
3387
|
ctx.clearRect(0, 0, 1, 1);
|
|
@@ -4073,7 +4101,7 @@ function paletteOf(el, now = performance.now()) {
|
|
|
4073
4101
|
palettes.set(el, { at: now, p });
|
|
4074
4102
|
return p;
|
|
4075
4103
|
}
|
|
4076
|
-
var reduced = (doc) => doc.defaultView
|
|
4104
|
+
var reduced = (doc) => reducedMotion(doc.defaultView);
|
|
4077
4105
|
function make(doc) {
|
|
4078
4106
|
return (tag, cls, text) => {
|
|
4079
4107
|
const node = doc.createElement(tag);
|
|
@@ -4664,7 +4692,7 @@ function createGraph(env) {
|
|
|
4664
4692
|
font: "meta",
|
|
4665
4693
|
align: "left"
|
|
4666
4694
|
});
|
|
4667
|
-
items.push(...k.value.texts(p,
|
|
4695
|
+
items.push(...k.value.texts(p, p.text));
|
|
4668
4696
|
}
|
|
4669
4697
|
items.push({
|
|
4670
4698
|
el: top,
|
|
@@ -5700,10 +5728,10 @@ function foldFaces(prev, p) {
|
|
|
5700
5728
|
function chevronTurn(p, edge) {
|
|
5701
5729
|
return (edge === "start" ? 180 : -180) * (1 - clamp01(p));
|
|
5702
5730
|
}
|
|
5703
|
-
function chevronFlip(f) {
|
|
5704
|
-
return
|
|
5731
|
+
function chevronFlip(f, edge) {
|
|
5732
|
+
return chevronTurn(f, edge);
|
|
5705
5733
|
}
|
|
5706
|
-
var FOLD_STYLE = { chevron: "flip", title: "travel", duration: 0.
|
|
5734
|
+
var FOLD_STYLE = { chevron: "flip", title: "travel", duration: 0.25 };
|
|
5707
5735
|
function foldStyle(options = {}) {
|
|
5708
5736
|
const duration = options.duration;
|
|
5709
5737
|
return {
|
|
@@ -5744,10 +5772,12 @@ function serializeLayout(layout) {
|
|
|
5744
5772
|
}
|
|
5745
5773
|
|
|
5746
5774
|
// src/ui/split.ts
|
|
5747
|
-
var FLIP = springMotion({ duration: 0.
|
|
5775
|
+
var FLIP = springMotion({ duration: 0.25, bounce: 0 });
|
|
5776
|
+
var FLIP_DEPTH = 28;
|
|
5748
5777
|
var SETTLE = springMotion({ duration: 0.3, bounce: 0 });
|
|
5749
5778
|
var CONTENT_BLUR = 3;
|
|
5750
5779
|
var LABEL_BLUR = 2;
|
|
5780
|
+
var COUNT_CLEAR = 0.12;
|
|
5751
5781
|
var put = (el, prop, value) => {
|
|
5752
5782
|
if (el.style.getPropertyValue(prop) !== value)
|
|
5753
5783
|
el.style.setProperty(prop, value);
|
|
@@ -5884,7 +5914,12 @@ function split(container, options) {
|
|
|
5884
5914
|
if (!row) {
|
|
5885
5915
|
head.dataset.toggles = "";
|
|
5886
5916
|
head.addEventListener("click", () => setCollapsed(spec.id, !collapsed[spec.id]));
|
|
5887
|
-
}
|
|
5917
|
+
} else
|
|
5918
|
+
head.addEventListener("dblclick", (e) => {
|
|
5919
|
+
if (e.target.closest(".knobs-pane-btn"))
|
|
5920
|
+
return;
|
|
5921
|
+
setCollapsed(spec.id, true);
|
|
5922
|
+
});
|
|
5888
5923
|
}
|
|
5889
5924
|
inner.append(head);
|
|
5890
5925
|
view.head = head;
|
|
@@ -6053,6 +6088,8 @@ function split(container, options) {
|
|
|
6053
6088
|
const label = v.railLabel;
|
|
6054
6089
|
const travel = morph && style.title === "travel" && Boolean(v.titleEl) && label.textContent === v.titleEl.textContent;
|
|
6055
6090
|
v.el.toggleAttribute("data-travel", travel && folding);
|
|
6091
|
+
if (v.countEl)
|
|
6092
|
+
put(v.countEl, "opacity", travel && folding && p > 0 ? Math.max(0, 1 - p / COUNT_CLEAR).toFixed(3) : "");
|
|
6056
6093
|
const k = 1 - p;
|
|
6057
6094
|
if (travel && !folding) {
|
|
6058
6095
|
put(label, "opacity", "0");
|
|
@@ -6080,8 +6117,9 @@ function split(container, options) {
|
|
|
6080
6117
|
if (style.chevron === "turn")
|
|
6081
6118
|
put(v.turn, "transform", k === 0 ? "" : `${move} rotate(${chevronTurn(p, v.edge).toFixed(2)}deg) ${size}`);
|
|
6082
6119
|
else {
|
|
6083
|
-
const
|
|
6084
|
-
|
|
6120
|
+
const turn = chevronFlip(v.flip.x, v.edge);
|
|
6121
|
+
const over = v.flip.resting ? turn === 0 ? "" : "scaleX(-1)" : `perspective(${FLIP_DEPTH}px) rotateY(${turn.toFixed(2)}deg)`;
|
|
6122
|
+
put(v.turn, "transform", k === 0 && !over ? "" : `${move} ${size} ${over}`);
|
|
6085
6123
|
}
|
|
6086
6124
|
} else {
|
|
6087
6125
|
const a = v.faces.rail;
|
|
@@ -7446,8 +7484,81 @@ function timeline(container, options) {
|
|
|
7446
7484
|
}
|
|
7447
7485
|
var PLAY = '<svg viewBox="0 0 16 16" aria-hidden="true"><path d="M5 3.6v8.8c0 .5.5.8.9.5l6.6-4.4c.4-.3.4-.8 0-1L5.9 3.1c-.4-.3-.9 0-.9.5Z" fill="currentColor"/></svg>';
|
|
7448
7486
|
var PAUSE = '<svg viewBox="0 0 16 16" aria-hidden="true"><rect x="4" y="3.2" width="2.8" height="9.6" rx="1" fill="currentColor"/><rect x="9.2" y="3.2" width="2.8" height="9.6" rx="1" fill="currentColor"/></svg>';
|
|
7487
|
+
// src/ui/scrollbar.ts
|
|
7488
|
+
function overlayScrollbar(scroller, content) {
|
|
7489
|
+
const doc = scroller.ownerDocument;
|
|
7490
|
+
const win = doc.defaultView;
|
|
7491
|
+
const track = doc.createElement("div");
|
|
7492
|
+
track.className = "knobs-scrollbar";
|
|
7493
|
+
track.setAttribute("aria-hidden", "true");
|
|
7494
|
+
const thumb = doc.createElement("div");
|
|
7495
|
+
thumb.className = "knobs-scrollbar-thumb";
|
|
7496
|
+
track.append(thumb);
|
|
7497
|
+
scroller.prepend(track);
|
|
7498
|
+
let size = 0;
|
|
7499
|
+
const update = () => {
|
|
7500
|
+
const view = scroller.clientHeight;
|
|
7501
|
+
const over = scroller.scrollHeight - view;
|
|
7502
|
+
const shown = over > 1 && view > 0;
|
|
7503
|
+
track.hidden = !shown;
|
|
7504
|
+
if (!shown)
|
|
7505
|
+
return;
|
|
7506
|
+
size = Math.max(20, view * view / (view + over));
|
|
7507
|
+
const y = Math.min(over, Math.max(0, scroller.scrollTop)) / over * (view - size);
|
|
7508
|
+
thumb.style.height = `${size.toFixed(1)}px`;
|
|
7509
|
+
thumb.style.transform = `translate3d(0,${y.toFixed(1)}px,0)`;
|
|
7510
|
+
};
|
|
7511
|
+
let idle = 0;
|
|
7512
|
+
const onScroll = () => {
|
|
7513
|
+
update();
|
|
7514
|
+
track.dataset.active = "";
|
|
7515
|
+
win.clearTimeout(idle);
|
|
7516
|
+
idle = win.setTimeout(() => delete track.dataset.active, 800);
|
|
7517
|
+
};
|
|
7518
|
+
scroller.addEventListener("scroll", onScroll, { passive: true });
|
|
7519
|
+
let drag;
|
|
7520
|
+
thumb.addEventListener("pointerdown", (e) => {
|
|
7521
|
+
if (e.button !== 0)
|
|
7522
|
+
return;
|
|
7523
|
+
e.preventDefault();
|
|
7524
|
+
e.stopPropagation();
|
|
7525
|
+
drag = { y: e.clientY, top: scroller.scrollTop, pointer: e.pointerId };
|
|
7526
|
+
thumb.setPointerCapture(e.pointerId);
|
|
7527
|
+
track.dataset.dragging = "";
|
|
7528
|
+
});
|
|
7529
|
+
thumb.addEventListener("pointermove", (e) => {
|
|
7530
|
+
if (!drag || e.pointerId !== drag.pointer)
|
|
7531
|
+
return;
|
|
7532
|
+
const view = scroller.clientHeight;
|
|
7533
|
+
const over = scroller.scrollHeight - view;
|
|
7534
|
+
scroller.scrollTop = drag.top + (e.clientY - drag.y) * over / Math.max(1, view - size);
|
|
7535
|
+
});
|
|
7536
|
+
const end = (e) => {
|
|
7537
|
+
if (!drag || e.pointerId !== drag.pointer)
|
|
7538
|
+
return;
|
|
7539
|
+
drag = undefined;
|
|
7540
|
+
delete track.dataset.dragging;
|
|
7541
|
+
};
|
|
7542
|
+
thumb.addEventListener("pointerup", end);
|
|
7543
|
+
thumb.addEventListener("pointercancel", end);
|
|
7544
|
+
thumb.addEventListener("lostpointercapture", end);
|
|
7545
|
+
const ro = new ResizeObserver(update);
|
|
7546
|
+
ro.observe(scroller);
|
|
7547
|
+
ro.observe(content);
|
|
7548
|
+
update();
|
|
7549
|
+
return {
|
|
7550
|
+
update,
|
|
7551
|
+
dispose() {
|
|
7552
|
+
ro.disconnect();
|
|
7553
|
+
win.clearTimeout(idle);
|
|
7554
|
+
scroller.removeEventListener("scroll", onScroll);
|
|
7555
|
+
track.remove();
|
|
7556
|
+
}
|
|
7557
|
+
};
|
|
7558
|
+
}
|
|
7559
|
+
|
|
7449
7560
|
// src/ui/tree.ts
|
|
7450
|
-
var MOVE = springMotion({ duration: 0.
|
|
7561
|
+
var MOVE = springMotion({ duration: 0.3, bounce: 0 });
|
|
7451
7562
|
var EDGE = 28;
|
|
7452
7563
|
function tree(container, options) {
|
|
7453
7564
|
const doc = container.ownerDocument;
|
|
@@ -7486,6 +7597,7 @@ function tree(container, options) {
|
|
|
7486
7597
|
empty.hidden = true;
|
|
7487
7598
|
root.append(space, line, empty);
|
|
7488
7599
|
container.append(root);
|
|
7600
|
+
const scrollbar = overlayScrollbar(root, space);
|
|
7489
7601
|
let h = 26;
|
|
7490
7602
|
let indent = 14;
|
|
7491
7603
|
let inset = 8;
|
|
@@ -8335,6 +8447,7 @@ function tree(container, options) {
|
|
|
8335
8447
|
loop.stop();
|
|
8336
8448
|
autoScroll.stop();
|
|
8337
8449
|
ro.disconnect();
|
|
8450
|
+
scrollbar.dispose();
|
|
8338
8451
|
dragging?.ghost.remove();
|
|
8339
8452
|
root.remove();
|
|
8340
8453
|
}
|
|
@@ -8680,11 +8793,7 @@ var SLIDE_BY = 0.12;
|
|
|
8680
8793
|
var EXIT_BLUR = 3;
|
|
8681
8794
|
var px = (x) => new Spring(x, LAYOUT.omega, LAYOUT.zeta, 0.05);
|
|
8682
8795
|
var unit = (x) => new Spring(x, ENTER.omega, ENTER.zeta, 0.0005);
|
|
8683
|
-
var drive = (s, m, target) =>
|
|
8684
|
-
s.omega = m.omega;
|
|
8685
|
-
s.zeta = m.zeta;
|
|
8686
|
-
return s.set(target);
|
|
8687
|
-
};
|
|
8796
|
+
var drive = (s, m, target) => tune(s, m).set(target);
|
|
8688
8797
|
var probed = new Map;
|
|
8689
8798
|
var smallest = (srcset) => {
|
|
8690
8799
|
let best;
|
|
@@ -9445,7 +9554,7 @@ function bento(container, options) {
|
|
|
9445
9554
|
}
|
|
9446
9555
|
zoomIn(t.id);
|
|
9447
9556
|
};
|
|
9448
|
-
const typing = (target) => target
|
|
9557
|
+
const typing = (target) => target !== root && isTypingTarget(target);
|
|
9449
9558
|
const reveal = (id) => {
|
|
9450
9559
|
const r = rectOf(id);
|
|
9451
9560
|
if (!r)
|
|
@@ -10512,7 +10621,7 @@ var ACTIVITY_ICONS = {
|
|
|
10512
10621
|
shipped: svg('<circle cx="8" cy="8" r="5.8"/><path d="m5.6 8.2 1.7 1.7 3.2-3.6"/>')
|
|
10513
10622
|
};
|
|
10514
10623
|
var PLAY2 = '<svg viewBox="0 0 8 8" aria-hidden="true"><path d="M1.5 1v6l5.2-3Z" fill="currentColor"/></svg>';
|
|
10515
|
-
var REFLOW = springMotion({ duration: 0.
|
|
10624
|
+
var REFLOW = springMotion({ duration: 0.3, bounce: 0 });
|
|
10516
10625
|
var OPEN = springMotion({ duration: 0.22, bounce: 0 });
|
|
10517
10626
|
var CLOSE = springMotion({ duration: 0.18, bounce: 0 });
|
|
10518
10627
|
var BLOOM = springMotion({ duration: 0.3, bounce: 0 });
|
|
@@ -10555,6 +10664,7 @@ function activity(container, options) {
|
|
|
10555
10664
|
space.append(hl, line);
|
|
10556
10665
|
root.append(empty, space);
|
|
10557
10666
|
container.append(root);
|
|
10667
|
+
const scrollbar = overlayScrollbar(root, space);
|
|
10558
10668
|
let heights = [32, 26];
|
|
10559
10669
|
const measure = () => {
|
|
10560
10670
|
syncFrame(root);
|
|
@@ -11178,6 +11288,7 @@ function activity(container, options) {
|
|
|
11178
11288
|
destroy() {
|
|
11179
11289
|
loop.stop();
|
|
11180
11290
|
ro.disconnect();
|
|
11291
|
+
scrollbar.dispose();
|
|
11181
11292
|
if (keysFrom === "page") {
|
|
11182
11293
|
win.removeEventListener("keydown", onKey);
|
|
11183
11294
|
win.removeEventListener("pointerdown", onPointer, true);
|