@estiva-app/ui 0.16.1 → 0.17.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 +3 -1
- package/dist/Button.d.ts.map +1 -1
- package/dist/Checkbox.d.ts +14 -1
- package/dist/Checkbox.d.ts.map +1 -1
- package/dist/FilePicker.d.ts +22 -0
- package/dist/FilePicker.d.ts.map +1 -0
- package/dist/Form.d.ts +34 -0
- package/dist/Form.d.ts.map +1 -0
- package/dist/IconButton.d.ts.map +1 -1
- package/dist/SearchInput.d.ts.map +1 -1
- package/dist/TextInput.d.ts.map +1 -1
- package/dist/Textarea.d.ts.map +1 -1
- package/dist/eslint/index.d.ts +1 -1
- package/dist/eslint/index.d.ts.map +1 -1
- package/dist/eslint/index.js +88 -8
- package/dist/eslint/index.js.map +4 -4
- package/dist/eslint/no-raw-element.d.ts +88 -0
- package/dist/eslint/no-raw-element.d.ts.map +1 -0
- package/dist/formBusy.d.ts +15 -0
- package/dist/formBusy.d.ts.map +1 -0
- package/dist/index.d.ts +2 -0
- package/dist/index.d.ts.map +1 -1
- package/dist/index.js +356 -239
- package/dist/index.js.map +4 -4
- package/package.json +1 -1
- package/src/Button.tsx +4 -1
- package/src/Checkbox.mdx +19 -1
- package/src/Checkbox.stories.tsx +12 -0
- package/src/Checkbox.test.tsx +54 -0
- package/src/Checkbox.tsx +40 -3
- package/src/FilePicker.mdx +49 -0
- package/src/FilePicker.stories.tsx +61 -0
- package/src/FilePicker.test.tsx +79 -0
- package/src/FilePicker.tsx +40 -0
- package/src/Form.mdx +68 -0
- package/src/Form.stories.tsx +68 -0
- package/src/Form.test.tsx +282 -0
- package/src/Form.tsx +113 -0
- package/src/IconButton.tsx +4 -1
- package/src/SearchInput.mdx +2 -2
- package/src/SearchInput.tsx +3 -1
- package/src/TextInput.mdx +2 -2
- package/src/TextInput.test.tsx +7 -0
- package/src/TextInput.tsx +4 -1
- package/src/Textarea.tsx +4 -1
- package/src/eslint/index.test.ts +24 -15
- package/src/eslint/index.ts +6 -5
- package/src/eslint/{no-raw-button.test.ts → no-raw-element.test.ts} +53 -8
- package/src/eslint/no-raw-element.ts +180 -0
- package/src/formBusy.ts +19 -0
- package/src/index.ts +2 -0
- package/stories/Choosing.mdx +3 -0
- package/dist/eslint/no-raw-button.d.ts +0 -11
- package/dist/eslint/no-raw-button.d.ts.map +0 -1
- package/src/eslint/no-raw-button.ts +0 -39
package/dist/index.js
CHANGED
|
@@ -244,6 +244,13 @@ function Card({
|
|
|
244
244
|
// src/IconButton.tsx
|
|
245
245
|
import { Button as BaseButton } from "@base-ui/react/button";
|
|
246
246
|
|
|
247
|
+
// src/formBusy.ts
|
|
248
|
+
import { createContext, useContext } from "react";
|
|
249
|
+
var FormBusyContext = createContext(false);
|
|
250
|
+
function useFormBusy() {
|
|
251
|
+
return useContext(FormBusyContext);
|
|
252
|
+
}
|
|
253
|
+
|
|
247
254
|
// src/Tooltip.tsx
|
|
248
255
|
import { Tooltip as BaseTooltip } from "@base-ui/react/tooltip";
|
|
249
256
|
|
|
@@ -337,11 +344,12 @@ function IconButton({
|
|
|
337
344
|
type = "button",
|
|
338
345
|
...props
|
|
339
346
|
}) {
|
|
347
|
+
const formBusy = useFormBusy();
|
|
340
348
|
const button = /* @__PURE__ */ jsx8(
|
|
341
349
|
BaseButton,
|
|
342
350
|
{
|
|
343
351
|
type,
|
|
344
|
-
disabled: disabled || !!disabledReason,
|
|
352
|
+
disabled: disabled || !!disabledReason || formBusy,
|
|
345
353
|
focusableWhenDisabled: !!disabledReason,
|
|
346
354
|
className: (state) => cn(
|
|
347
355
|
// `shrink-0` stops a flex parent squashing the button; `self-center`
|
|
@@ -682,11 +690,12 @@ function Button({
|
|
|
682
690
|
...props
|
|
683
691
|
}) {
|
|
684
692
|
const hasLeadingIcon = !!leadingIcon;
|
|
693
|
+
const formBusy = useFormBusy();
|
|
685
694
|
const button = /* @__PURE__ */ jsxs8(
|
|
686
695
|
BaseButton3,
|
|
687
696
|
{
|
|
688
697
|
type,
|
|
689
|
-
disabled: disabled || !!disabledReason,
|
|
698
|
+
disabled: disabled || !!disabledReason || formBusy,
|
|
690
699
|
focusableWhenDisabled: !!disabledReason,
|
|
691
700
|
className: (state) => cn(
|
|
692
701
|
// No `self-center` here, deliberately — `IconButton` needs it and this
|
|
@@ -732,8 +741,9 @@ function Button({
|
|
|
732
741
|
|
|
733
742
|
// src/Checkbox.tsx
|
|
734
743
|
import { Checkbox as BaseCheckbox } from "@base-ui/react/checkbox";
|
|
744
|
+
import { Field as BaseField } from "@base-ui/react/field";
|
|
735
745
|
import { IconCheck } from "@tabler/icons-react";
|
|
736
|
-
import { jsx as jsx14 } from "react/jsx-runtime";
|
|
746
|
+
import { jsx as jsx14, jsxs as jsxs9 } from "react/jsx-runtime";
|
|
737
747
|
function squareClasses(checked, disabled, interactive, className) {
|
|
738
748
|
return cn(
|
|
739
749
|
"inline-flex items-center justify-center size-4 shrink-0 rounded-sm border transition-colors",
|
|
@@ -744,11 +754,19 @@ function squareClasses(checked, disabled, interactive, className) {
|
|
|
744
754
|
);
|
|
745
755
|
}
|
|
746
756
|
var tickClasses = (checked) => cn("flex", !checked && "invisible");
|
|
747
|
-
|
|
757
|
+
var WORDS_CLASSES = "text-body-2 text-text-primary";
|
|
758
|
+
function Checkbox({ checked, onChange, disabled: ownDisabled = false, label, className, ...aria }) {
|
|
759
|
+
const formBusy = useFormBusy();
|
|
760
|
+
const disabled = ownDisabled || formBusy;
|
|
748
761
|
if (!onChange) {
|
|
749
|
-
|
|
762
|
+
const picture = /* @__PURE__ */ jsx14("span", { "aria-hidden": "true", className: squareClasses(checked, disabled, false, className), children: /* @__PURE__ */ jsx14("span", { className: tickClasses(checked), children: /* @__PURE__ */ jsx14(IconCheck, { size: 12, stroke: 3 }) }) });
|
|
763
|
+
if (label === void 0) return picture;
|
|
764
|
+
return /* @__PURE__ */ jsxs9("span", { className: "flex items-center gap-2", children: [
|
|
765
|
+
picture,
|
|
766
|
+
/* @__PURE__ */ jsx14("span", { className: WORDS_CLASSES, children: label })
|
|
767
|
+
] });
|
|
750
768
|
}
|
|
751
|
-
|
|
769
|
+
const box = /* @__PURE__ */ jsx14(
|
|
752
770
|
BaseCheckbox.Root,
|
|
753
771
|
{
|
|
754
772
|
checked,
|
|
@@ -761,10 +779,15 @@ function Checkbox({ checked, onChange, disabled = false, className, ...aria }) {
|
|
|
761
779
|
children: /* @__PURE__ */ jsx14(BaseCheckbox.Indicator, { keepMounted: true, className: (state) => tickClasses(state.checked), children: /* @__PURE__ */ jsx14(IconCheck, { size: 12, stroke: 3 }) })
|
|
762
780
|
}
|
|
763
781
|
);
|
|
782
|
+
if (label === void 0) return box;
|
|
783
|
+
return /* @__PURE__ */ jsx14(BaseField.Root, { disabled, children: /* @__PURE__ */ jsxs9(BaseField.Label, { className: cn("flex items-center gap-2", !disabled && "cursor-pointer"), children: [
|
|
784
|
+
box,
|
|
785
|
+
/* @__PURE__ */ jsx14("span", { className: WORDS_CLASSES, children: label })
|
|
786
|
+
] }) });
|
|
764
787
|
}
|
|
765
788
|
|
|
766
789
|
// src/Chip.tsx
|
|
767
|
-
import { jsx as jsx15, jsxs as
|
|
790
|
+
import { jsx as jsx15, jsxs as jsxs10 } from "react/jsx-runtime";
|
|
768
791
|
var typeStyles = {
|
|
769
792
|
neutral: "bg-bg-inset text-text-primary",
|
|
770
793
|
brand: "bg-accent-muted text-accent-primary signal:border signal:border-accent-outline",
|
|
@@ -774,7 +797,7 @@ var typeStyles = {
|
|
|
774
797
|
error: "bg-error-muted text-error-default signal:border signal:border-error-outline"
|
|
775
798
|
};
|
|
776
799
|
function Chip({ type = "neutral", label, leadingIcon, trailingIcon, className }) {
|
|
777
|
-
return /* @__PURE__ */
|
|
800
|
+
return /* @__PURE__ */ jsxs10("div", { className: cn("inline-flex min-w-0 items-center justify-center gap-1.5 rounded-full max-h-[20px] px-2 py-1", typeStyles[type], className), children: [
|
|
778
801
|
leadingIcon && /* @__PURE__ */ jsx15("span", { className: "flex size-3 shrink-0 items-center justify-center", children: leadingIcon }),
|
|
779
802
|
label && // A chip given a `max-w-*` cuts a long label with an ellipsis instead
|
|
780
803
|
// of growing past it — Ship's project chip on an issue row
|
|
@@ -791,8 +814,8 @@ function Chip({ type = "neutral", label, leadingIcon, trailingIcon, className })
|
|
|
791
814
|
|
|
792
815
|
// src/CommandPalette.tsx
|
|
793
816
|
import {
|
|
794
|
-
createContext as
|
|
795
|
-
useContext as
|
|
817
|
+
createContext as createContext3,
|
|
818
|
+
useContext as useContext3,
|
|
796
819
|
useEffect,
|
|
797
820
|
useLayoutEffect as useLayoutEffect2,
|
|
798
821
|
useMemo as useMemo2,
|
|
@@ -810,7 +833,7 @@ import { Combobox } from "@base-ui/react/combobox";
|
|
|
810
833
|
import { IconX as IconX3 } from "@tabler/icons-react";
|
|
811
834
|
|
|
812
835
|
// src/Menu.tsx
|
|
813
|
-
import { createContext, useContext } from "react";
|
|
836
|
+
import { createContext as createContext2, useContext as useContext2 } from "react";
|
|
814
837
|
import { IconChevronRight } from "@tabler/icons-react";
|
|
815
838
|
import { Menu as BaseMenu } from "@base-ui/react/menu";
|
|
816
839
|
|
|
@@ -836,8 +859,8 @@ function SectionLabel({ children, className }) {
|
|
|
836
859
|
}
|
|
837
860
|
|
|
838
861
|
// src/Menu.tsx
|
|
839
|
-
import { Fragment as Fragment2, jsx as jsx17, jsxs as
|
|
840
|
-
var MenuContext =
|
|
862
|
+
import { Fragment as Fragment2, jsx as jsx17, jsxs as jsxs11 } from "react/jsx-runtime";
|
|
863
|
+
var MenuContext = createContext2(null);
|
|
841
864
|
function MenuPanel({ children, className, ...props }) {
|
|
842
865
|
return /* @__PURE__ */ jsx17(
|
|
843
866
|
"div",
|
|
@@ -869,7 +892,7 @@ var VIEWPORT_PAD2 = 8;
|
|
|
869
892
|
var HOVER_OPEN_DELAY = 0;
|
|
870
893
|
var HOVER_CLOSE_DELAY = 150;
|
|
871
894
|
function Menu({ trigger, align = "left", openOnHover = false, open, onOpenChange, actionsRef, children, className, contentClassName }) {
|
|
872
|
-
return /* @__PURE__ */
|
|
895
|
+
return /* @__PURE__ */ jsxs11(
|
|
873
896
|
BaseMenu.Root,
|
|
874
897
|
{
|
|
875
898
|
open,
|
|
@@ -911,13 +934,13 @@ function Menu({ trigger, align = "left", openOnHover = false, open, onOpenChange
|
|
|
911
934
|
);
|
|
912
935
|
}
|
|
913
936
|
function MenuSub({ label, leading, selected, children, className }) {
|
|
914
|
-
const menu =
|
|
937
|
+
const menu = useContext2(MenuContext);
|
|
915
938
|
if (!isProduction() && menu?.openOnHover) {
|
|
916
939
|
console.error(
|
|
917
940
|
'[@estiva-app/ui] Menu: `openOnHover` and `MenuSub` cannot be used together \u2014 leaving the submenu panel strands the menu open. Open this menu on a press instead. See Menu.mdx, "Hover-opened menus".'
|
|
918
941
|
);
|
|
919
942
|
}
|
|
920
|
-
return /* @__PURE__ */
|
|
943
|
+
return /* @__PURE__ */ jsxs11(BaseMenu.SubmenuRoot, { children: [
|
|
921
944
|
/* @__PURE__ */ jsx17(
|
|
922
945
|
BaseMenu.SubmenuTrigger,
|
|
923
946
|
{
|
|
@@ -974,9 +997,9 @@ function menuItemClassName({ size, selected, className }) {
|
|
|
974
997
|
}
|
|
975
998
|
function MenuItemBody({ label, children, size = "default", description, leading, trailing, hint, shortcut, submenu, destructive, selected }) {
|
|
976
999
|
const edge = trailing ?? (shortcut ? /* @__PURE__ */ jsx17(Kbd, { children: shortcut }) : submenu ? /* @__PURE__ */ jsx17(IconChevronRight, { size: 16, stroke: 1.5, className: "shrink-0 text-text-muted" }) : null);
|
|
977
|
-
return /* @__PURE__ */
|
|
1000
|
+
return /* @__PURE__ */ jsxs11(Fragment2, { children: [
|
|
978
1001
|
leading && /* @__PURE__ */ jsx17("span", { className: "flex shrink-0 items-center", children: leading }),
|
|
979
|
-
children ?? /* @__PURE__ */
|
|
1002
|
+
children ?? /* @__PURE__ */ jsxs11("span", { className: cn("flex min-w-0 flex-1 flex-col", size === "tall" && "gap-[2px]"), children: [
|
|
980
1003
|
/* @__PURE__ */ jsx17("span", { className: cn("truncate text-body-2", destructive ? "text-error-default" : "text-text-primary"), children: label }),
|
|
981
1004
|
description && /* @__PURE__ */ jsx17("span", { className: "truncate text-caption text-text-secondary", children: description })
|
|
982
1005
|
] }),
|
|
@@ -984,7 +1007,7 @@ function MenuItemBody({ label, children, size = "default", description, leading,
|
|
|
984
1007
|
// the wider of the two and never changes, so revealing the hint moves
|
|
985
1008
|
// nothing. No transition here either — the hint switches on the same
|
|
986
1009
|
// :hover / `selected` as the fill, in the same frame.
|
|
987
|
-
/* @__PURE__ */
|
|
1010
|
+
/* @__PURE__ */ jsxs11("span", { className: "grid shrink-0 items-center justify-items-end [&>*]:col-start-1 [&>*]:row-start-1", children: [
|
|
988
1011
|
edge && /* @__PURE__ */ jsx17("span", { className: cn("flex items-center", hint && "group-hover:opacity-0 group-data-[highlighted]:opacity-0", hint && selected && "opacity-0"), children: edge }),
|
|
989
1012
|
hint && /* @__PURE__ */ jsx17("span", { className: cn("flex items-center opacity-0 group-hover:opacity-100 group-data-[highlighted]:opacity-100", selected && "opacity-100"), children: hint })
|
|
990
1013
|
] })
|
|
@@ -1008,7 +1031,7 @@ function MenuItem({ label, children, size = "default", description, leading, tra
|
|
|
1008
1031
|
}
|
|
1009
1032
|
);
|
|
1010
1033
|
const rowClassName = menuItemClassName({ size, selected, className });
|
|
1011
|
-
if (!
|
|
1034
|
+
if (!useContext2(MenuContext)) {
|
|
1012
1035
|
return /* @__PURE__ */ jsx17("button", { type: "button", className: rowClassName, ...props, children: body });
|
|
1013
1036
|
}
|
|
1014
1037
|
return /* @__PURE__ */ jsx17(
|
|
@@ -1023,21 +1046,21 @@ function MenuItem({ label, children, size = "default", description, leading, tra
|
|
|
1023
1046
|
);
|
|
1024
1047
|
}
|
|
1025
1048
|
function EnterHint({ target }) {
|
|
1026
|
-
return /* @__PURE__ */
|
|
1049
|
+
return /* @__PURE__ */ jsxs11("span", { className: "flex shrink-0 items-center gap-1.5 text-text-muted", children: [
|
|
1027
1050
|
/* @__PURE__ */ jsx17(Kbd, { children: "\u21A9 Enter" }),
|
|
1028
1051
|
target && /* @__PURE__ */ jsx17("span", { className: "text-menu signal:font-mono signal:text-small signal:tracking-wider", children: target })
|
|
1029
1052
|
] });
|
|
1030
1053
|
}
|
|
1031
1054
|
function MenuSection({ label, children, className }) {
|
|
1032
|
-
const inMenu =
|
|
1055
|
+
const inMenu = useContext2(MenuContext) !== null;
|
|
1033
1056
|
const heading = /* @__PURE__ */ jsx17("div", { className: cn("flex h-8 items-center px-2", className), children: /* @__PURE__ */ jsx17(SectionLabel, { className: "text-text-secondary", children: label }) });
|
|
1034
1057
|
if (!inMenu) {
|
|
1035
|
-
return /* @__PURE__ */
|
|
1058
|
+
return /* @__PURE__ */ jsxs11("div", { className: "flex flex-col", children: [
|
|
1036
1059
|
heading,
|
|
1037
1060
|
children
|
|
1038
1061
|
] });
|
|
1039
1062
|
}
|
|
1040
|
-
return /* @__PURE__ */
|
|
1063
|
+
return /* @__PURE__ */ jsxs11(BaseMenu.Group, { className: "flex flex-col", children: [
|
|
1041
1064
|
/* @__PURE__ */ jsx17(BaseMenu.GroupLabel, { render: heading }),
|
|
1042
1065
|
children
|
|
1043
1066
|
] });
|
|
@@ -1047,7 +1070,7 @@ function MenuRow({ children, className }) {
|
|
|
1047
1070
|
}
|
|
1048
1071
|
|
|
1049
1072
|
// src/ChipInput.tsx
|
|
1050
|
-
import { jsx as jsx18, jsxs as
|
|
1073
|
+
import { jsx as jsx18, jsxs as jsxs12 } from "react/jsx-runtime";
|
|
1051
1074
|
var CHIP_BOX = (
|
|
1052
1075
|
// Curved, not a pill (Katerina, 2026-09-01): the Avatar keeps its own
|
|
1053
1076
|
// rounded-sm corners — never a forced circle — and the chip's corner
|
|
@@ -1058,7 +1081,7 @@ var CHIP_LABEL = "text-caption font-medium text-text-primary";
|
|
|
1058
1081
|
var CHIP_REMOVE = "size-4 flex items-center justify-center rounded-full hover:bg-bg-hover text-text-secondary";
|
|
1059
1082
|
var chipPadding = (leading, removable) => cn(leading ? "pl-[2px]" : "pl-2", removable ? "pr-1" : "pr-2");
|
|
1060
1083
|
function InputChip({ label, leading, onRemove, removeLabel, truncate, className }) {
|
|
1061
|
-
return /* @__PURE__ */
|
|
1084
|
+
return /* @__PURE__ */ jsxs12("div", { className: cn(CHIP_BOX, chipPadding(!!leading, !!onRemove), className), children: [
|
|
1062
1085
|
leading && /* @__PURE__ */ jsx18("span", { className: "flex shrink-0 items-center", children: leading }),
|
|
1063
1086
|
/* @__PURE__ */ jsx18("span", { className: cn(CHIP_LABEL, truncate && "min-w-0 truncate"), children: label }),
|
|
1064
1087
|
onRemove && /* @__PURE__ */ jsx18(
|
|
@@ -1124,7 +1147,7 @@ function ChipInput({
|
|
|
1124
1147
|
setQuery("");
|
|
1125
1148
|
}
|
|
1126
1149
|
}
|
|
1127
|
-
return /* @__PURE__ */
|
|
1150
|
+
return /* @__PURE__ */ jsxs12(
|
|
1128
1151
|
Combobox.Root,
|
|
1129
1152
|
{
|
|
1130
1153
|
multiple: true,
|
|
@@ -1141,8 +1164,8 @@ function ChipInput({
|
|
|
1141
1164
|
filter,
|
|
1142
1165
|
itemToStringLabel: (option) => option.label,
|
|
1143
1166
|
children: [
|
|
1144
|
-
/* @__PURE__ */
|
|
1145
|
-
value.map((option) => /* @__PURE__ */
|
|
1167
|
+
/* @__PURE__ */ jsxs12(Combobox.Chips, { ref: setBox, className: "bg-bg-inset border border-border-default hover:border-border-strong focus-within:border-border-focus focus-within:hover:border-border-focus rounded-lg px-3 py-1.5 flex flex-wrap items-center gap-1.5 transition-colors min-h-[38px] cursor-text signal:transition-shadow signal:focus-within:shadow-focus-ring", children: [
|
|
1168
|
+
value.map((option) => /* @__PURE__ */ jsxs12(Combobox.Chip, { className: cn(CHIP_BOX, chipPadding(!!chipLeading, true)), children: [
|
|
1146
1169
|
chipLeading && /* @__PURE__ */ jsx18("span", { className: "flex shrink-0 items-center", children: chipLeading(option) }),
|
|
1147
1170
|
/* @__PURE__ */ jsx18("span", { className: CHIP_LABEL, children: option.label }),
|
|
1148
1171
|
/* @__PURE__ */ jsx18(Combobox.ChipRemove, { className: CHIP_REMOVE, "aria-label": `Remove ${option.label}`, children: /* @__PURE__ */ jsx18(IconX3, { size: 10, stroke: 1.5 }) })
|
|
@@ -1193,12 +1216,12 @@ var VIEWPORT_PAD3 = 8;
|
|
|
1193
1216
|
|
|
1194
1217
|
// src/EmptyState.tsx
|
|
1195
1218
|
import { IconMessage2 } from "@tabler/icons-react";
|
|
1196
|
-
import { jsx as jsx19, jsxs as
|
|
1219
|
+
import { jsx as jsx19, jsxs as jsxs13 } from "react/jsx-runtime";
|
|
1197
1220
|
function EmptyState({ icon, message, scope = "page", className }) {
|
|
1198
1221
|
if (scope === "section") {
|
|
1199
1222
|
return /* @__PURE__ */ jsx19("p", { className: cn("text-caption text-text-muted", className), children: message });
|
|
1200
1223
|
}
|
|
1201
|
-
return /* @__PURE__ */
|
|
1224
|
+
return /* @__PURE__ */ jsxs13("div", { className: cn("flex flex-1 flex-col items-center justify-center gap-2", className), children: [
|
|
1202
1225
|
/* @__PURE__ */ jsx19("span", { className: "text-text-secondary", children: icon ?? /* @__PURE__ */ jsx19(IconMessage2, { size: 16, stroke: 1.5 }) }),
|
|
1203
1226
|
/* @__PURE__ */ jsx19("p", { className: "text-body-2 text-text-secondary text-center", children: message })
|
|
1204
1227
|
] });
|
|
@@ -1206,8 +1229,8 @@ function EmptyState({ icon, message, scope = "page", className }) {
|
|
|
1206
1229
|
|
|
1207
1230
|
// src/Field.tsx
|
|
1208
1231
|
import { cloneElement, isValidElement } from "react";
|
|
1209
|
-
import { Field as
|
|
1210
|
-
import { jsx as jsx20, jsxs as
|
|
1232
|
+
import { Field as BaseField2 } from "@base-ui/react/field";
|
|
1233
|
+
import { jsx as jsx20, jsxs as jsxs14 } from "react/jsx-runtime";
|
|
1211
1234
|
var LINE_STYLES = {
|
|
1212
1235
|
helper: "text-caption text-text-muted",
|
|
1213
1236
|
warning: "text-caption text-warning-default",
|
|
@@ -1217,14 +1240,14 @@ function Field({ label, required = false, helper, error, children }) {
|
|
|
1217
1240
|
const control = required && isValidElement(children) ? cloneElement(children, {
|
|
1218
1241
|
"aria-required": children.props["aria-required"] ?? true
|
|
1219
1242
|
}) : children;
|
|
1220
|
-
return /* @__PURE__ */
|
|
1221
|
-
/* @__PURE__ */
|
|
1243
|
+
return /* @__PURE__ */ jsxs14(BaseField2.Root, { invalid: !!error, className: "flex flex-col gap-2", children: [
|
|
1244
|
+
/* @__PURE__ */ jsxs14(BaseField2.Label, { className: cn("text-input-label text-text-primary", required && "flex items-center"), children: [
|
|
1222
1245
|
label,
|
|
1223
1246
|
required && /* @__PURE__ */ jsx20("span", { "aria-hidden": "true", className: "text-error-default ml-0.5", children: "*" })
|
|
1224
1247
|
] }),
|
|
1225
|
-
/* @__PURE__ */
|
|
1248
|
+
/* @__PURE__ */ jsxs14("div", { className: "flex flex-col gap-1.5", children: [
|
|
1226
1249
|
control,
|
|
1227
|
-
error != null ? /* @__PURE__ */ jsx20(
|
|
1250
|
+
error != null ? /* @__PURE__ */ jsx20(BaseField2.Error, { match: true, className: LINE_STYLES.error, children: error }) : helper != null ? /* @__PURE__ */ jsx20(BaseField2.Description, { className: LINE_STYLES.helper, children: helper }) : null
|
|
1228
1251
|
] })
|
|
1229
1252
|
] });
|
|
1230
1253
|
}
|
|
@@ -1233,13 +1256,13 @@ function FieldLine({ tone = "helper", children, className }) {
|
|
|
1233
1256
|
}
|
|
1234
1257
|
|
|
1235
1258
|
// src/Skeleton.tsx
|
|
1236
|
-
import { jsx as jsx21, jsxs as
|
|
1259
|
+
import { jsx as jsx21, jsxs as jsxs15 } from "react/jsx-runtime";
|
|
1237
1260
|
function SkeletonBar({ className, style }) {
|
|
1238
1261
|
return /* @__PURE__ */ jsx21("div", { className: cn("bg-bg-inset rounded-sm animate-pulse", className), style });
|
|
1239
1262
|
}
|
|
1240
1263
|
var ROW_BAR_WIDTHS = [150, 100, 170, 120, 90, 140, 110, 160];
|
|
1241
1264
|
function SkeletonRow({ barWidth = 130 }) {
|
|
1242
|
-
return /* @__PURE__ */
|
|
1265
|
+
return /* @__PURE__ */ jsxs15("div", { className: "flex items-center gap-2 px-2 h-[32px] rounded-lg", children: [
|
|
1243
1266
|
/* @__PURE__ */ jsx21(SkeletonBar, { className: "w-4 h-4 shrink-0" }),
|
|
1244
1267
|
/* @__PURE__ */ jsx21(SkeletonBar, { className: "h-3.5", style: { width: barWidth } })
|
|
1245
1268
|
] });
|
|
@@ -1249,10 +1272,10 @@ function SkeletonList({ rows = 8, className }) {
|
|
|
1249
1272
|
}
|
|
1250
1273
|
|
|
1251
1274
|
// src/CommandPalette.tsx
|
|
1252
|
-
import { Fragment as Fragment3, jsx as jsx22, jsxs as
|
|
1253
|
-
var PaletteContext =
|
|
1275
|
+
import { Fragment as Fragment3, jsx as jsx22, jsxs as jsxs16 } from "react/jsx-runtime";
|
|
1276
|
+
var PaletteContext = createContext3(null);
|
|
1254
1277
|
function usePalette(part) {
|
|
1255
|
-
const palette =
|
|
1278
|
+
const palette = useContext3(PaletteContext);
|
|
1256
1279
|
if (!palette) throw new Error(`[@estiva-app/ui] ${part} must be inside a CommandPalette.`);
|
|
1257
1280
|
return palette;
|
|
1258
1281
|
}
|
|
@@ -1275,7 +1298,7 @@ function CommandPalette({ open, onOpenChange, label, where, modKey = "Ctrl", chi
|
|
|
1275
1298
|
return () => cancelAnimationFrame(frame);
|
|
1276
1299
|
});
|
|
1277
1300
|
const context = useMemo2(() => ({ where, modKey, popupRef }), [where, modKey]);
|
|
1278
|
-
return /* @__PURE__ */ jsx22(Dialog.Root, { open, onOpenChange: (next) => onOpenChange(next), children: /* @__PURE__ */
|
|
1301
|
+
return /* @__PURE__ */ jsx22(Dialog.Root, { open, onOpenChange: (next) => onOpenChange(next), children: /* @__PURE__ */ jsxs16(Dialog.Portal, { children: [
|
|
1279
1302
|
/* @__PURE__ */ jsx22(Dialog.Backdrop, { className: "fixed inset-0 z-40 bg-scrim" }),
|
|
1280
1303
|
/* @__PURE__ */ jsx22(Dialog.Viewport, { className: "fixed inset-0 z-50 flex items-start justify-center pt-[16vh]", children: /* @__PURE__ */ jsx22(
|
|
1281
1304
|
Dialog.Popup,
|
|
@@ -1304,9 +1327,9 @@ function useBack(chip, popupRef) {
|
|
|
1304
1327
|
}
|
|
1305
1328
|
function Footer({ keys }) {
|
|
1306
1329
|
const { where } = usePalette("The footer");
|
|
1307
|
-
return /* @__PURE__ */
|
|
1330
|
+
return /* @__PURE__ */ jsxs16("div", { className: "flex h-9 shrink-0 items-center gap-4 border-t border-border-subtle px-5 text-caption text-text-secondary signal:font-mono signal:text-small signal:text-text-muted", children: [
|
|
1308
1331
|
/* @__PURE__ */ jsx22("span", { className: "min-w-0 flex-1 truncate", children: where }),
|
|
1309
|
-
keys.map(([key, word]) => /* @__PURE__ */
|
|
1332
|
+
keys.map(([key, word]) => /* @__PURE__ */ jsxs16("span", { className: "flex shrink-0 items-center gap-1.5", children: [
|
|
1310
1333
|
/* @__PURE__ */ jsx22(Kbd, { children: key }),
|
|
1311
1334
|
" ",
|
|
1312
1335
|
word
|
|
@@ -1384,7 +1407,7 @@ function CommandPaletteSearch({ query, onQueryChange, placeholder, groups, chip,
|
|
|
1384
1407
|
...chip && query === "" ? [["Backspace", "back"]] : [],
|
|
1385
1408
|
["Esc", "close"]
|
|
1386
1409
|
];
|
|
1387
|
-
return /* @__PURE__ */
|
|
1410
|
+
return /* @__PURE__ */ jsxs16(
|
|
1388
1411
|
Autocomplete.Root,
|
|
1389
1412
|
{
|
|
1390
1413
|
items,
|
|
@@ -1407,7 +1430,7 @@ function CommandPaletteSearch({ query, onQueryChange, placeholder, groups, chip,
|
|
|
1407
1430
|
setLitId(id);
|
|
1408
1431
|
},
|
|
1409
1432
|
children: [
|
|
1410
|
-
/* @__PURE__ */
|
|
1433
|
+
/* @__PURE__ */ jsxs16("div", { className: "flex h-12 shrink-0 items-center gap-3 border-b border-border-subtle px-5", children: [
|
|
1411
1434
|
/* @__PURE__ */ jsx22(IconSearch, { size: 16, stroke: 1.5, className: "shrink-0 text-text-secondary" }),
|
|
1412
1435
|
chip && /* @__PURE__ */ jsx22(LevelChip, { chip, onBack: back }),
|
|
1413
1436
|
/* @__PURE__ */ jsx22(
|
|
@@ -1422,9 +1445,9 @@ function CommandPaletteSearch({ query, onQueryChange, placeholder, groups, chip,
|
|
|
1422
1445
|
}
|
|
1423
1446
|
)
|
|
1424
1447
|
] }),
|
|
1425
|
-
/* @__PURE__ */
|
|
1448
|
+
/* @__PURE__ */ jsxs16(ScrollArea, { viewportClassName: "max-h-[420px]", contentClassName: "flex flex-col p-2", children: [
|
|
1426
1449
|
children != null && /* @__PURE__ */ jsx22("div", { className: "flex flex-col gap-2 px-3 pb-2 pt-3", children }),
|
|
1427
|
-
/* @__PURE__ */ jsx22(Autocomplete.List, { className: "flex flex-col", children: (group) => /* @__PURE__ */
|
|
1450
|
+
/* @__PURE__ */ jsx22(Autocomplete.List, { className: "flex flex-col", children: (group) => /* @__PURE__ */ jsxs16(Autocomplete.Group, { items: group.items, className: "flex flex-col", children: [
|
|
1428
1451
|
/* @__PURE__ */ jsx22(Autocomplete.GroupLabel, { className: "flex h-7 shrink-0 items-center px-3", children: /* @__PURE__ */ jsx22(SectionLabel, { className: "text-text-secondary", children: group.value }) }),
|
|
1429
1452
|
/* @__PURE__ */ jsx22(Autocomplete.Collection, { children: (row) => (
|
|
1430
1453
|
/* The menu row, as the list's own option — the way Select
|
|
@@ -1442,7 +1465,7 @@ function CommandPaletteSearch({ query, onQueryChange, placeholder, groups, chip,
|
|
|
1442
1465
|
) }, row.id)
|
|
1443
1466
|
) })
|
|
1444
1467
|
] }, group.value) }),
|
|
1445
|
-
/* @__PURE__ */ jsx22(Autocomplete.Status, { className: "flex items-center gap-2 px-3 [&:not(:empty)]:h-8", children: pending && /* @__PURE__ */
|
|
1468
|
+
/* @__PURE__ */ jsx22(Autocomplete.Status, { className: "flex items-center gap-2 px-3 [&:not(:empty)]:h-8", children: pending && /* @__PURE__ */ jsxs16(Fragment3, { children: [
|
|
1446
1469
|
/* @__PURE__ */ jsx22(IconLoader22, { size: 12, stroke: 1.5, className: "shrink-0 animate-spin text-text-muted" }),
|
|
1447
1470
|
/* @__PURE__ */ jsx22("span", { className: "text-caption text-text-muted", children: pending })
|
|
1448
1471
|
] }) }),
|
|
@@ -1518,13 +1541,13 @@ function CommandPaletteForm({ chip, icon, submitLabel, onSubmit, submitWaits, wo
|
|
|
1518
1541
|
...backNamed ? [["Backspace", "back"]] : [],
|
|
1519
1542
|
["Esc", "close"]
|
|
1520
1543
|
];
|
|
1521
|
-
return /* @__PURE__ */
|
|
1522
|
-
/* @__PURE__ */
|
|
1544
|
+
return /* @__PURE__ */ jsxs16("div", { ref: frameRef, tabIndex: -1, onKeyDown, onFocus: measure, onBlur: measure, onInput: measure, className: "flex min-h-0 flex-col outline-none", children: [
|
|
1545
|
+
/* @__PURE__ */ jsxs16("div", { className: "flex h-12 shrink-0 items-center gap-3 border-b border-border-subtle px-5", children: [
|
|
1523
1546
|
icon != null && /* @__PURE__ */ jsx22("span", { className: "flex shrink-0 items-center text-text-secondary", children: icon }),
|
|
1524
1547
|
/* @__PURE__ */ jsx22(LevelChip, { chip, onBack: back })
|
|
1525
1548
|
] }),
|
|
1526
1549
|
/* @__PURE__ */ jsx22(ScrollArea, { viewportClassName: "max-h-[420px]", contentClassName: "flex flex-col px-5 py-4", children: /* @__PURE__ */ jsx22("fieldset", { "data-command-palette-fields": "", disabled: busy, className: "contents", children: /* @__PURE__ */ jsx22("div", { className: "flex flex-col gap-4", children }) }) }),
|
|
1527
|
-
/* @__PURE__ */
|
|
1550
|
+
/* @__PURE__ */ jsxs16("div", { className: "flex shrink-0 items-center gap-3 px-5 pb-4", children: [
|
|
1528
1551
|
/* @__PURE__ */ jsx22("div", { className: "min-w-0 flex-1", children: working ? /* @__PURE__ */ jsx22(FieldLine, { children: working.line }) : error ? /* @__PURE__ */ jsx22(FieldLine, { tone: "error", children: error }) : null }),
|
|
1529
1552
|
/* @__PURE__ */ jsx22(
|
|
1530
1553
|
Button,
|
|
@@ -1543,8 +1566,8 @@ function CommandPaletteForm({ chip, icon, submitLabel, onSubmit, submitWaits, wo
|
|
|
1543
1566
|
}
|
|
1544
1567
|
var BAR_WIDTHS = ["w-4/5", "w-3/5", "w-2/3"];
|
|
1545
1568
|
function CommandPaletteWorking({ children, bars = 2 }) {
|
|
1546
|
-
return /* @__PURE__ */
|
|
1547
|
-
/* @__PURE__ */
|
|
1569
|
+
return /* @__PURE__ */ jsxs16("div", { role: "status", className: "flex flex-col gap-2", children: [
|
|
1570
|
+
/* @__PURE__ */ jsxs16("span", { className: "flex items-center gap-2 text-caption text-text-secondary", children: [
|
|
1548
1571
|
/* @__PURE__ */ jsx22(IconLoader22, { size: 14, stroke: 1.5, className: "shrink-0 animate-spin" }),
|
|
1549
1572
|
children
|
|
1550
1573
|
] }),
|
|
@@ -1553,7 +1576,7 @@ function CommandPaletteWorking({ children, bars = 2 }) {
|
|
|
1553
1576
|
}
|
|
1554
1577
|
function CommandPaletteAnswer({ children, note }) {
|
|
1555
1578
|
const paragraphs = children.split(/\n\s*\n/).filter((p) => p.trim() !== "");
|
|
1556
|
-
return /* @__PURE__ */
|
|
1579
|
+
return /* @__PURE__ */ jsxs16("div", { className: "flex flex-col gap-2", children: [
|
|
1557
1580
|
paragraphs.map((paragraph, i) => /* @__PURE__ */ jsx22("p", { className: "whitespace-pre-wrap text-body-2 text-text-primary", children: paragraph.split(/\s*(\[\d+\])/).map(
|
|
1558
1581
|
(part, j) => /^\[\d+\]$/.test(part) ? /* @__PURE__ */ jsx22("sup", { className: "ml-0.5 font-mono text-small text-accent-primary", children: part.slice(1, -1) }, j) : part
|
|
1559
1582
|
) }, i)),
|
|
@@ -1565,7 +1588,7 @@ function CommandPaletteQuote({ children }) {
|
|
|
1565
1588
|
}
|
|
1566
1589
|
|
|
1567
1590
|
// src/InlineChip.tsx
|
|
1568
|
-
import { Fragment as Fragment4, jsx as jsx23, jsxs as
|
|
1591
|
+
import { Fragment as Fragment4, jsx as jsx23, jsxs as jsxs17 } from "react/jsx-runtime";
|
|
1569
1592
|
var INLINE_CHIP_CLASSES = "inline-flex h-[1.4em] items-center gap-1 rounded-sm px-1 mx-0.5 align-top text-body-2 font-normal select-none";
|
|
1570
1593
|
var INLINE_CHIP_TONE_CLASSES = {
|
|
1571
1594
|
/** A thing or a place — anything that is not a person. */
|
|
@@ -1587,7 +1610,7 @@ function inlineChipClassName(tone, className) {
|
|
|
1587
1610
|
return cn(INLINE_CHIP_CLASSES, INLINE_CHIP_TONE_CLASSES[tone], className);
|
|
1588
1611
|
}
|
|
1589
1612
|
function InlineChip({ tone = "neutral", icon, href, className, children, ...props }) {
|
|
1590
|
-
const body = /* @__PURE__ */
|
|
1613
|
+
const body = /* @__PURE__ */ jsxs17(Fragment4, { children: [
|
|
1591
1614
|
icon && /* @__PURE__ */ jsx23("span", { className: "flex size-4 shrink-0 items-center justify-center text-text-secondary", children: icon }),
|
|
1592
1615
|
children
|
|
1593
1616
|
] });
|
|
@@ -1603,11 +1626,11 @@ import { useCallback, useRef as useRef3 } from "react";
|
|
|
1603
1626
|
|
|
1604
1627
|
// src/Divider.tsx
|
|
1605
1628
|
import { Separator } from "@base-ui/react/separator";
|
|
1606
|
-
import { jsx as jsx24, jsxs as
|
|
1629
|
+
import { jsx as jsx24, jsxs as jsxs18 } from "react/jsx-runtime";
|
|
1607
1630
|
function Divider({ orientation = "horizontal", label, tone = "default", className }) {
|
|
1608
1631
|
if (label && orientation === "horizontal") {
|
|
1609
1632
|
const line = tone === "warning" ? "bg-warning-muted" : "bg-border-subtle";
|
|
1610
|
-
return /* @__PURE__ */
|
|
1633
|
+
return /* @__PURE__ */ jsxs18(
|
|
1611
1634
|
Separator,
|
|
1612
1635
|
{
|
|
1613
1636
|
orientation: "horizontal",
|
|
@@ -1631,13 +1654,13 @@ function Divider({ orientation = "horizontal", label, tone = "default", classNam
|
|
|
1631
1654
|
}
|
|
1632
1655
|
|
|
1633
1656
|
// src/Person.tsx
|
|
1634
|
-
import { jsx as jsx25, jsxs as
|
|
1657
|
+
import { jsx as jsx25, jsxs as jsxs19 } from "react/jsx-runtime";
|
|
1635
1658
|
function Person({ name, picture, fallback = "\u2014", size = 20, className }) {
|
|
1636
1659
|
return (
|
|
1637
1660
|
// gap-2: the face-to-name distance is one rule (8px) wherever a person
|
|
1638
1661
|
// appears — Katerina, 2026-09-01, set on Person so PersonTrigger and every
|
|
1639
1662
|
// row agree by construction.
|
|
1640
|
-
/* @__PURE__ */
|
|
1663
|
+
/* @__PURE__ */ jsxs19("span", { className: cn("flex min-w-0 items-center gap-2", className), children: [
|
|
1641
1664
|
/* @__PURE__ */ jsx25(Avatar, { name, src: picture, size }),
|
|
1642
1665
|
/* @__PURE__ */ jsx25("span", { className: cn("truncate", !name && "text-text-muted"), children: name ?? fallback })
|
|
1643
1666
|
] })
|
|
@@ -1647,7 +1670,7 @@ function Person({ name, picture, fallback = "\u2014", size = 20, className }) {
|
|
|
1647
1670
|
// src/PersonTrigger.tsx
|
|
1648
1671
|
import { Button as BaseButton5 } from "@base-ui/react/button";
|
|
1649
1672
|
import { IconChevronDown } from "@tabler/icons-react";
|
|
1650
|
-
import { jsx as jsx26, jsxs as
|
|
1673
|
+
import { jsx as jsx26, jsxs as jsxs20 } from "react/jsx-runtime";
|
|
1651
1674
|
function PersonTrigger({ name, picture, fallback, size, open = false, compact = false, className, ...props }) {
|
|
1652
1675
|
if (compact) {
|
|
1653
1676
|
return /* @__PURE__ */ jsx26(
|
|
@@ -1663,7 +1686,7 @@ function PersonTrigger({ name, picture, fallback, size, open = false, compact =
|
|
|
1663
1686
|
}
|
|
1664
1687
|
);
|
|
1665
1688
|
}
|
|
1666
|
-
return /* @__PURE__ */
|
|
1689
|
+
return /* @__PURE__ */ jsxs20(
|
|
1667
1690
|
BaseButton5,
|
|
1668
1691
|
{
|
|
1669
1692
|
type: "button",
|
|
@@ -1689,7 +1712,7 @@ function PersonTrigger({ name, picture, fallback, size, open = false, compact =
|
|
|
1689
1712
|
}
|
|
1690
1713
|
|
|
1691
1714
|
// src/IdentityMenu.tsx
|
|
1692
|
-
import { Fragment as Fragment5, jsx as jsx27, jsxs as
|
|
1715
|
+
import { Fragment as Fragment5, jsx as jsx27, jsxs as jsxs21 } from "react/jsx-runtime";
|
|
1693
1716
|
function IdentityPanel({ className, onClose = () => {
|
|
1694
1717
|
}, ...rest }) {
|
|
1695
1718
|
return /* @__PURE__ */ jsx27(MenuPanel, { className: cn("w-72", className), children: /* @__PURE__ */ jsx27(IdentityRows, { ...rest, onClose }) });
|
|
@@ -1700,23 +1723,23 @@ function IdentityRows({ me, signedIn, relayUrl, idBase, onCopyKey, onSignOut, on
|
|
|
1700
1723
|
action();
|
|
1701
1724
|
};
|
|
1702
1725
|
const appRows = typeof children === "function" ? children(onClose) : children;
|
|
1703
|
-
return /* @__PURE__ */
|
|
1704
|
-
/* @__PURE__ */
|
|
1726
|
+
return /* @__PURE__ */ jsxs21(Fragment5, { children: [
|
|
1727
|
+
/* @__PURE__ */ jsxs21(MenuSection, { label: signedIn ? "Signed in as" : "Acting as", children: [
|
|
1705
1728
|
/* @__PURE__ */ jsx27(MenuRow, { children: /* @__PURE__ */ jsx27(Person, { name: me.name, picture: me.picture, fallback: "Anonymous", size: 28, className: "text-body-2-strong" }) }),
|
|
1706
1729
|
/* @__PURE__ */ jsx27(Note, { children: signedIn ? "Your Estiva ID. The same person you are in every Estiva app." : "A key held by this browser only. Nobody else knows who you are." }),
|
|
1707
|
-
me.email && /* @__PURE__ */
|
|
1730
|
+
me.email && /* @__PURE__ */ jsxs21(Note, { children: [
|
|
1708
1731
|
me.email,
|
|
1709
1732
|
" \xB7 known to Estiva, never published to the relay"
|
|
1710
1733
|
] })
|
|
1711
1734
|
] }),
|
|
1712
|
-
relayUrl && /* @__PURE__ */
|
|
1735
|
+
relayUrl && /* @__PURE__ */ jsxs21(Fragment5, { children: [
|
|
1713
1736
|
/* @__PURE__ */ jsx27(Divider, { className: "mx-0 my-2" }),
|
|
1714
|
-
/* @__PURE__ */
|
|
1737
|
+
/* @__PURE__ */ jsxs21(MenuSection, { label: "Workspace", children: [
|
|
1715
1738
|
/* @__PURE__ */ jsx27(MenuRow, { children: /* @__PURE__ */ jsx27("span", { className: "break-all font-mono text-caption text-text-primary", children: relayUrl }) }),
|
|
1716
1739
|
/* @__PURE__ */ jsx27(Note, { children: "Everyone on this relay shares this workspace, in every app." })
|
|
1717
1740
|
] })
|
|
1718
1741
|
] }),
|
|
1719
|
-
appRows && /* @__PURE__ */
|
|
1742
|
+
appRows && /* @__PURE__ */ jsxs21(Fragment5, { children: [
|
|
1720
1743
|
/* @__PURE__ */ jsx27(Divider, { className: "mx-0 my-2" }),
|
|
1721
1744
|
appRows
|
|
1722
1745
|
] }),
|
|
@@ -1778,15 +1801,99 @@ function Note({ children }) {
|
|
|
1778
1801
|
return /* @__PURE__ */ jsx27("span", { className: "px-2 pb-1.5 text-caption text-text-secondary", children });
|
|
1779
1802
|
}
|
|
1780
1803
|
|
|
1804
|
+
// src/FilePicker.tsx
|
|
1805
|
+
import { forwardRef } from "react";
|
|
1806
|
+
import { jsx as jsx28 } from "react/jsx-runtime";
|
|
1807
|
+
var FilePicker = forwardRef(function FilePicker2({ onPick, ...props }, ref) {
|
|
1808
|
+
return /* @__PURE__ */ jsx28(
|
|
1809
|
+
"input",
|
|
1810
|
+
{
|
|
1811
|
+
ref,
|
|
1812
|
+
type: "file",
|
|
1813
|
+
"aria-hidden": "true",
|
|
1814
|
+
tabIndex: -1,
|
|
1815
|
+
className: "hidden",
|
|
1816
|
+
...props,
|
|
1817
|
+
onChange: (event) => {
|
|
1818
|
+
const files = Array.from(event.target.files ?? []);
|
|
1819
|
+
event.target.value = "";
|
|
1820
|
+
if (files.length > 0) onPick(files);
|
|
1821
|
+
}
|
|
1822
|
+
}
|
|
1823
|
+
);
|
|
1824
|
+
});
|
|
1825
|
+
|
|
1826
|
+
// src/Form.tsx
|
|
1827
|
+
import { useLayoutEffect as useLayoutEffect3, useRef as useRef4 } from "react";
|
|
1828
|
+
import { Fieldset } from "@base-ui/react/fieldset";
|
|
1829
|
+
import { Form as BaseForm } from "@base-ui/react/form";
|
|
1830
|
+
import { jsx as jsx29 } from "react/jsx-runtime";
|
|
1831
|
+
var CONTROL2 = 'input:not([type="hidden"]), textarea, select, button, [role="checkbox"], [role="combobox"], [tabindex]:not([tabindex="-1"])';
|
|
1832
|
+
function usable(element) {
|
|
1833
|
+
return element instanceof HTMLElement && element.isConnected && element.matches(CONTROL2) && !element.matches(":disabled") && element.getAttribute("aria-disabled") !== "true";
|
|
1834
|
+
}
|
|
1835
|
+
function Form({ onSubmit, busy: ownBusy = false, className, children, ...props }) {
|
|
1836
|
+
const outerBusy = useFormBusy();
|
|
1837
|
+
const busy = ownBusy || outerBusy;
|
|
1838
|
+
const form = useRef4(null);
|
|
1839
|
+
const sender = useRef4(null);
|
|
1840
|
+
const holding = useRef4(false);
|
|
1841
|
+
const lastInside = useRef4(null);
|
|
1842
|
+
useLayoutEffect3(() => {
|
|
1843
|
+
const element = form.current;
|
|
1844
|
+
if (!element) return;
|
|
1845
|
+
if (busy) {
|
|
1846
|
+
const active = document.activeElement;
|
|
1847
|
+
const from = active && active !== element && element.contains(active) ? active : !active || active === document.body ? lastInside.current : null;
|
|
1848
|
+
if (from?.isConnected) {
|
|
1849
|
+
sender.current = from;
|
|
1850
|
+
holding.current = true;
|
|
1851
|
+
element.focus();
|
|
1852
|
+
}
|
|
1853
|
+
return;
|
|
1854
|
+
}
|
|
1855
|
+
if (!holding.current) return;
|
|
1856
|
+
holding.current = false;
|
|
1857
|
+
if (document.activeElement !== element && document.activeElement !== document.body) return;
|
|
1858
|
+
const invalid = Array.from(element.querySelectorAll("[data-invalid]")).find(usable);
|
|
1859
|
+
const target = invalid ?? (usable(sender.current) ? sender.current : Array.from(element.querySelectorAll(CONTROL2)).find(usable));
|
|
1860
|
+
sender.current = null;
|
|
1861
|
+
target?.focus();
|
|
1862
|
+
}, [busy]);
|
|
1863
|
+
return /* @__PURE__ */ jsx29(
|
|
1864
|
+
BaseForm,
|
|
1865
|
+
{
|
|
1866
|
+
ref: form,
|
|
1867
|
+
...props,
|
|
1868
|
+
tabIndex: busy ? -1 : props.tabIndex,
|
|
1869
|
+
className: cn("outline-none", className),
|
|
1870
|
+
onFocus: (event) => {
|
|
1871
|
+
if (event.target !== form.current) lastInside.current = event.target;
|
|
1872
|
+
props.onFocus?.(event);
|
|
1873
|
+
},
|
|
1874
|
+
onBlur: (event) => {
|
|
1875
|
+
const next = event.relatedTarget;
|
|
1876
|
+
if (next && !form.current?.contains(next)) lastInside.current = null;
|
|
1877
|
+
props.onBlur?.(event);
|
|
1878
|
+
},
|
|
1879
|
+
onSubmit: (event) => {
|
|
1880
|
+
event.preventDefault();
|
|
1881
|
+
void onSubmit();
|
|
1882
|
+
},
|
|
1883
|
+
children: /* @__PURE__ */ jsx29(Fieldset.Root, { disabled: busy, className: "contents", children: /* @__PURE__ */ jsx29(FormBusyContext.Provider, { value: busy, children }) })
|
|
1884
|
+
}
|
|
1885
|
+
);
|
|
1886
|
+
}
|
|
1887
|
+
|
|
1781
1888
|
// src/Select.tsx
|
|
1782
1889
|
import { IconCheck as IconCheck2, IconChevronDown as IconChevronDown2 } from "@tabler/icons-react";
|
|
1783
1890
|
import { Select as BaseSelect } from "@base-ui/react/select";
|
|
1784
|
-
import { jsx as
|
|
1891
|
+
import { jsx as jsx30, jsxs as jsxs22 } from "react/jsx-runtime";
|
|
1785
1892
|
var GAP4 = 4;
|
|
1786
1893
|
var VIEWPORT_PAD4 = 8;
|
|
1787
1894
|
function Select({ value, onChange, options, size = "default", ariaLabel, placeholder = "Select\u2026", disabled, className, ...aria }) {
|
|
1788
1895
|
const selected = options.find((o) => o.value === value);
|
|
1789
|
-
return /* @__PURE__ */
|
|
1896
|
+
return /* @__PURE__ */ jsxs22(
|
|
1790
1897
|
BaseSelect.Root,
|
|
1791
1898
|
{
|
|
1792
1899
|
value,
|
|
@@ -1794,7 +1901,7 @@ function Select({ value, onChange, options, size = "default", ariaLabel, placeho
|
|
|
1794
1901
|
disabled,
|
|
1795
1902
|
modal: false,
|
|
1796
1903
|
children: [
|
|
1797
|
-
/* @__PURE__ */
|
|
1904
|
+
/* @__PURE__ */ jsxs22(
|
|
1798
1905
|
BaseSelect.Trigger,
|
|
1799
1906
|
{
|
|
1800
1907
|
"aria-label": ariaLabel,
|
|
@@ -1821,20 +1928,20 @@ function Select({ value, onChange, options, size = "default", ariaLabel, placeho
|
|
|
1821
1928
|
className
|
|
1822
1929
|
),
|
|
1823
1930
|
children: [
|
|
1824
|
-
/* @__PURE__ */
|
|
1825
|
-
selected?.leading && /* @__PURE__ */
|
|
1826
|
-
/* @__PURE__ */
|
|
1931
|
+
/* @__PURE__ */ jsxs22("span", { className: cn("flex min-w-0 items-center gap-2", !selected && "text-text-muted"), children: [
|
|
1932
|
+
selected?.leading && /* @__PURE__ */ jsx30("span", { className: "flex shrink-0 items-center", children: selected.leading }),
|
|
1933
|
+
/* @__PURE__ */ jsx30(BaseSelect.Value, { className: "truncate", children: () => selected?.label ?? placeholder })
|
|
1827
1934
|
] }),
|
|
1828
|
-
/* @__PURE__ */
|
|
1935
|
+
/* @__PURE__ */ jsx30(
|
|
1829
1936
|
BaseSelect.Icon,
|
|
1830
1937
|
{
|
|
1831
|
-
render: /* @__PURE__ */
|
|
1938
|
+
render: /* @__PURE__ */ jsx30(IconChevronDown2, { size: size === "small" ? 14 : 16, stroke: 1.5, className: "shrink-0 text-text-secondary" })
|
|
1832
1939
|
}
|
|
1833
1940
|
)
|
|
1834
1941
|
]
|
|
1835
1942
|
}
|
|
1836
1943
|
),
|
|
1837
|
-
/* @__PURE__ */
|
|
1944
|
+
/* @__PURE__ */ jsx30(BaseSelect.Portal, { children: /* @__PURE__ */ jsx30(
|
|
1838
1945
|
BaseSelect.Positioner,
|
|
1839
1946
|
{
|
|
1840
1947
|
side: "bottom",
|
|
@@ -1843,25 +1950,25 @@ function Select({ value, onChange, options, size = "default", ariaLabel, placeho
|
|
|
1843
1950
|
collisionPadding: VIEWPORT_PAD4,
|
|
1844
1951
|
alignItemWithTrigger: false,
|
|
1845
1952
|
className: "z-50 data-[anchor-hidden]:hidden",
|
|
1846
|
-
children: /* @__PURE__ */
|
|
1953
|
+
children: /* @__PURE__ */ jsx30(
|
|
1847
1954
|
BaseSelect.Popup,
|
|
1848
1955
|
{
|
|
1849
|
-
render: /* @__PURE__ */
|
|
1956
|
+
render: /* @__PURE__ */ jsx30(MenuPanel, {}),
|
|
1850
1957
|
className: "min-w-[var(--anchor-width)] p-0",
|
|
1851
|
-
children: /* @__PURE__ */
|
|
1958
|
+
children: /* @__PURE__ */ jsx30(ScrollArea, { viewportClassName: "max-h-[min(288px,var(--available-height))]", contentClassName: "flex flex-col p-2", children: options.map((option) => /* @__PURE__ */ jsxs22(
|
|
1852
1959
|
BaseSelect.Item,
|
|
1853
1960
|
{
|
|
1854
1961
|
value: option.value,
|
|
1855
1962
|
className: cn(menuItemClassName({ size: "default" }), "justify-between data-[selected]:font-medium"),
|
|
1856
1963
|
children: [
|
|
1857
|
-
/* @__PURE__ */
|
|
1858
|
-
option.leading && /* @__PURE__ */
|
|
1859
|
-
/* @__PURE__ */
|
|
1964
|
+
/* @__PURE__ */ jsxs22("span", { className: "flex min-w-0 items-center gap-2", children: [
|
|
1965
|
+
option.leading && /* @__PURE__ */ jsx30("span", { className: "flex shrink-0 items-center", children: option.leading }),
|
|
1966
|
+
/* @__PURE__ */ jsx30(BaseSelect.ItemText, { className: "truncate text-body-2 text-text-primary", children: option.label })
|
|
1860
1967
|
] }),
|
|
1861
|
-
/* @__PURE__ */
|
|
1968
|
+
/* @__PURE__ */ jsx30(
|
|
1862
1969
|
BaseSelect.ItemIndicator,
|
|
1863
1970
|
{
|
|
1864
|
-
render: /* @__PURE__ */
|
|
1971
|
+
render: /* @__PURE__ */ jsx30(IconCheck2, { size: 16, stroke: 1.5, className: "shrink-0 text-text-secondary" })
|
|
1865
1972
|
}
|
|
1866
1973
|
)
|
|
1867
1974
|
]
|
|
@@ -1878,17 +1985,20 @@ function Select({ value, onChange, options, size = "default", ariaLabel, placeho
|
|
|
1878
1985
|
}
|
|
1879
1986
|
|
|
1880
1987
|
// src/TextInput.tsx
|
|
1881
|
-
import { forwardRef } from "react";
|
|
1988
|
+
import { forwardRef as forwardRef2 } from "react";
|
|
1882
1989
|
import { Input } from "@base-ui/react/input";
|
|
1883
|
-
import { jsx as
|
|
1884
|
-
var TextInput =
|
|
1885
|
-
return /* @__PURE__ */
|
|
1990
|
+
import { jsx as jsx31 } from "react/jsx-runtime";
|
|
1991
|
+
var TextInput = forwardRef2(function TextInput2({ className, type = "text", size = "default", ...props }, ref) {
|
|
1992
|
+
return /* @__PURE__ */ jsx31(
|
|
1886
1993
|
Input,
|
|
1887
1994
|
{
|
|
1888
1995
|
ref,
|
|
1889
1996
|
type,
|
|
1890
1997
|
className: cn(
|
|
1891
|
-
|
|
1998
|
+
// The border strengthens on hover, as Select's and ChipInput's do (Katerina, 16 September:
|
|
1999
|
+
// "aren't there hover states in text input and text area?"). Focus comes after hover in
|
|
2000
|
+
// Tailwind's order, so a focused field keeps the focus border under the pointer.
|
|
2001
|
+
"bg-bg-inset border border-border-default hover:border-border-strong focus:border-border-focus rounded-lg",
|
|
1892
2002
|
// The small size is the small Select's trigger, class for class.
|
|
1893
2003
|
size === "default" && "px-3 py-2 text-input-value",
|
|
1894
2004
|
size === "small" && "h-6 px-2 text-caption",
|
|
@@ -1904,17 +2014,20 @@ var TextInput = forwardRef(function TextInput2({ className, type = "text", size
|
|
|
1904
2014
|
});
|
|
1905
2015
|
|
|
1906
2016
|
// src/Textarea.tsx
|
|
1907
|
-
import { forwardRef as
|
|
1908
|
-
import { Field as
|
|
1909
|
-
import { jsx as
|
|
1910
|
-
var Textarea =
|
|
1911
|
-
return /* @__PURE__ */
|
|
1912
|
-
|
|
2017
|
+
import { forwardRef as forwardRef3 } from "react";
|
|
2018
|
+
import { Field as BaseField3 } from "@base-ui/react/field";
|
|
2019
|
+
import { jsx as jsx32 } from "react/jsx-runtime";
|
|
2020
|
+
var Textarea = forwardRef3(function Textarea2({ className, ...props }, ref) {
|
|
2021
|
+
return /* @__PURE__ */ jsx32(
|
|
2022
|
+
BaseField3.Control,
|
|
1913
2023
|
{
|
|
1914
2024
|
ref,
|
|
1915
|
-
render: /* @__PURE__ */
|
|
2025
|
+
render: /* @__PURE__ */ jsx32("textarea", {}),
|
|
1916
2026
|
className: cn(
|
|
1917
|
-
|
|
2027
|
+
// The border strengthens on hover, as Select's and ChipInput's do (Katerina, 16 September:
|
|
2028
|
+
// "aren't there hover states in text input and text area?"). Focus comes after hover in
|
|
2029
|
+
// Tailwind's order, so a focused field keeps the focus border under the pointer.
|
|
2030
|
+
"bg-bg-inset border border-border-default hover:border-border-strong focus:border-border-focus rounded-lg px-3 py-2",
|
|
1918
2031
|
"text-input-value text-text-primary placeholder:text-text-muted",
|
|
1919
2032
|
"resize-none outline-none transition-colors",
|
|
1920
2033
|
"disabled:pointer-events-none disabled:bg-bg-disabled disabled:text-text-disabled",
|
|
@@ -1930,24 +2043,24 @@ var Textarea = forwardRef2(function Textarea2({ className, ...props }, ref) {
|
|
|
1930
2043
|
import { useState as useState4 } from "react";
|
|
1931
2044
|
|
|
1932
2045
|
// src/DialogShell.tsx
|
|
1933
|
-
import { useRef as
|
|
2046
|
+
import { useRef as useRef5 } from "react";
|
|
1934
2047
|
import { Dialog as Dialog2 } from "@base-ui/react/dialog";
|
|
1935
2048
|
import { AlertDialog } from "@base-ui/react/alert-dialog";
|
|
1936
2049
|
import { IconX as IconX4 } from "@tabler/icons-react";
|
|
1937
|
-
import { jsx as
|
|
2050
|
+
import { jsx as jsx33, jsxs as jsxs23 } from "react/jsx-runtime";
|
|
1938
2051
|
function DialogShell({ title, onClose, headerContent, footer, children, bodyClassName, bodyMaxHeight, width = 502, alert = false }) {
|
|
1939
2052
|
const Parts = alert ? AlertDialog : Dialog2;
|
|
1940
|
-
const popupRef =
|
|
1941
|
-
return /* @__PURE__ */
|
|
2053
|
+
const popupRef = useRef5(null);
|
|
2054
|
+
return /* @__PURE__ */ jsx33(
|
|
1942
2055
|
Parts.Root,
|
|
1943
2056
|
{
|
|
1944
2057
|
open: true,
|
|
1945
2058
|
onOpenChange: (open) => {
|
|
1946
2059
|
if (!open) onClose();
|
|
1947
2060
|
},
|
|
1948
|
-
children: /* @__PURE__ */
|
|
1949
|
-
/* @__PURE__ */
|
|
1950
|
-
/* @__PURE__ */
|
|
2061
|
+
children: /* @__PURE__ */ jsxs23(Parts.Portal, { children: [
|
|
2062
|
+
/* @__PURE__ */ jsx33(Parts.Backdrop, { className: "fixed inset-0 z-40 bg-scrim" }),
|
|
2063
|
+
/* @__PURE__ */ jsx33("div", { className: "fixed inset-0 z-50 flex items-center justify-center pointer-events-none", children: /* @__PURE__ */ jsxs23(
|
|
1951
2064
|
Parts.Popup,
|
|
1952
2065
|
{
|
|
1953
2066
|
ref: popupRef,
|
|
@@ -1956,16 +2069,16 @@ function DialogShell({ title, onClose, headerContent, footer, children, bodyClas
|
|
|
1956
2069
|
className: "bg-bg-elevated border border-border-subtle rounded-lg shadow-lg pointer-events-auto flex flex-col overflow-hidden outline-none",
|
|
1957
2070
|
style: { width },
|
|
1958
2071
|
children: [
|
|
1959
|
-
/* @__PURE__ */
|
|
1960
|
-
headerContent ?? /* @__PURE__ */
|
|
1961
|
-
/* @__PURE__ */
|
|
2072
|
+
/* @__PURE__ */ jsxs23("div", { className: "h-12 flex items-center justify-between pl-5 pr-4 border-b border-border-subtle shrink-0", children: [
|
|
2073
|
+
headerContent ?? /* @__PURE__ */ jsx33(Parts.Title, { className: "text-h4 text-text-primary", render: /* @__PURE__ */ jsx33("span", {}), children: title }),
|
|
2074
|
+
/* @__PURE__ */ jsx33(
|
|
1962
2075
|
Parts.Close,
|
|
1963
2076
|
{
|
|
1964
|
-
render: /* @__PURE__ */
|
|
2077
|
+
render: /* @__PURE__ */ jsx33(IconButton, { tooltip: "Close", "aria-label": "Close", children: /* @__PURE__ */ jsx33(IconX4, { size: 16, stroke: 1.5 }) })
|
|
1965
2078
|
}
|
|
1966
2079
|
)
|
|
1967
2080
|
] }),
|
|
1968
|
-
bodyMaxHeight ? /* @__PURE__ */
|
|
2081
|
+
bodyMaxHeight ? /* @__PURE__ */ jsx33(
|
|
1969
2082
|
ScrollArea,
|
|
1970
2083
|
{
|
|
1971
2084
|
className: cn(footer != null && "border-b border-border-subtle"),
|
|
@@ -1973,8 +2086,8 @@ function DialogShell({ title, onClose, headerContent, footer, children, bodyClas
|
|
|
1973
2086
|
contentClassName: cn("pl-5 pr-4 py-4", bodyClassName),
|
|
1974
2087
|
children
|
|
1975
2088
|
}
|
|
1976
|
-
) : /* @__PURE__ */
|
|
1977
|
-
footer != null && /* @__PURE__ */
|
|
2089
|
+
) : /* @__PURE__ */ jsx33("div", { className: cn("pl-5 pr-4 py-4", footer != null && "border-b border-border-subtle", bodyClassName), children }),
|
|
2090
|
+
footer != null && /* @__PURE__ */ jsx33("div", { className: "h-12 flex items-center justify-end gap-2 pl-5 pr-4 shrink-0", children: footer })
|
|
1978
2091
|
]
|
|
1979
2092
|
}
|
|
1980
2093
|
) })
|
|
@@ -1984,7 +2097,7 @@ function DialogShell({ title, onClose, headerContent, footer, children, bodyClas
|
|
|
1984
2097
|
}
|
|
1985
2098
|
|
|
1986
2099
|
// src/ConfirmDialog.tsx
|
|
1987
|
-
import { Fragment as Fragment6, jsx as
|
|
2100
|
+
import { Fragment as Fragment6, jsx as jsx34, jsxs as jsxs24 } from "react/jsx-runtime";
|
|
1988
2101
|
function ConfirmDialog({ title, children, confirmLabel, destructive = false, onConfirm, onClose }) {
|
|
1989
2102
|
const [busy, setBusy] = useState4(false);
|
|
1990
2103
|
const confirm = async () => {
|
|
@@ -1996,16 +2109,16 @@ function ConfirmDialog({ title, children, confirmLabel, destructive = false, onC
|
|
|
1996
2109
|
setBusy(false);
|
|
1997
2110
|
}
|
|
1998
2111
|
};
|
|
1999
|
-
return /* @__PURE__ */
|
|
2112
|
+
return /* @__PURE__ */ jsx34(
|
|
2000
2113
|
DialogShell,
|
|
2001
2114
|
{
|
|
2002
2115
|
alert: true,
|
|
2003
2116
|
title,
|
|
2004
2117
|
onClose,
|
|
2005
2118
|
bodyClassName: "flex flex-col gap-3 text-body-2 text-text-primary",
|
|
2006
|
-
footer: /* @__PURE__ */
|
|
2007
|
-
/* @__PURE__ */
|
|
2008
|
-
/* @__PURE__ */
|
|
2119
|
+
footer: /* @__PURE__ */ jsxs24(Fragment6, { children: [
|
|
2120
|
+
/* @__PURE__ */ jsx34(Button, { variant: "muted", onClick: onClose, disabled: busy, children: "Cancel" }),
|
|
2121
|
+
/* @__PURE__ */ jsx34(Button, { variant: destructive ? "destructive" : "primary", onClick: () => void confirm(), disabled: busy, children: confirmLabel })
|
|
2009
2122
|
] }),
|
|
2010
2123
|
children
|
|
2011
2124
|
}
|
|
@@ -2013,15 +2126,15 @@ function ConfirmDialog({ title, children, confirmLabel, destructive = false, onC
|
|
|
2013
2126
|
}
|
|
2014
2127
|
|
|
2015
2128
|
// src/EditableText.tsx
|
|
2016
|
-
import { useEffect as useEffect2, useRef as
|
|
2017
|
-
import { Field as
|
|
2129
|
+
import { useEffect as useEffect2, useRef as useRef6, useState as useState5 } from "react";
|
|
2130
|
+
import { Field as BaseField4 } from "@base-ui/react/field";
|
|
2018
2131
|
import { Input as Input2 } from "@base-ui/react/input";
|
|
2019
|
-
import { jsx as
|
|
2132
|
+
import { jsx as jsx35 } from "react/jsx-runtime";
|
|
2020
2133
|
function EditableText({ value, display, displayNode, placeholder, onCommit, multiline = false, className, label, readOnly = false }) {
|
|
2021
2134
|
const [editing, setEditing] = useState5(false);
|
|
2022
2135
|
const [draft, setDraft] = useState5(value);
|
|
2023
2136
|
const [busy, setBusy] = useState5(false);
|
|
2024
|
-
const fieldRef =
|
|
2137
|
+
const fieldRef = useRef6(null);
|
|
2025
2138
|
useEffect2(() => {
|
|
2026
2139
|
if (editing) {
|
|
2027
2140
|
fieldRef.current?.focus();
|
|
@@ -2074,7 +2187,7 @@ function EditableText({ value, display, displayNode, placeholder, onCommit, mult
|
|
|
2074
2187
|
written and never read. Read-only, this is a line of text: whatever
|
|
2075
2188
|
names the region around it (a `Field`, a `Property`) names this too.
|
|
2076
2189
|
*/
|
|
2077
|
-
/* @__PURE__ */
|
|
2190
|
+
/* @__PURE__ */ jsx35(
|
|
2078
2191
|
"div",
|
|
2079
2192
|
{
|
|
2080
2193
|
className: cn("w-full px-2 py-1", multiline && !displayNode && "whitespace-pre-wrap", display ?? value ? "text-text-primary" : "text-text-muted", className),
|
|
@@ -2084,11 +2197,11 @@ function EditableText({ value, display, displayNode, placeholder, onCommit, mult
|
|
|
2084
2197
|
);
|
|
2085
2198
|
}
|
|
2086
2199
|
if (editing) {
|
|
2087
|
-
return multiline ? /* @__PURE__ */
|
|
2088
|
-
|
|
2200
|
+
return multiline ? /* @__PURE__ */ jsx35(
|
|
2201
|
+
BaseField4.Control,
|
|
2089
2202
|
{
|
|
2090
2203
|
ref: fieldRef,
|
|
2091
|
-
render: /* @__PURE__ */
|
|
2204
|
+
render: /* @__PURE__ */ jsx35("textarea", { rows: 4 }),
|
|
2092
2205
|
"aria-label": label,
|
|
2093
2206
|
value: draft,
|
|
2094
2207
|
disabled: busy,
|
|
@@ -2097,7 +2210,7 @@ function EditableText({ value, display, displayNode, placeholder, onCommit, mult
|
|
|
2097
2210
|
onBlur: () => void commit(),
|
|
2098
2211
|
className: fieldClass
|
|
2099
2212
|
}
|
|
2100
|
-
) : /* @__PURE__ */
|
|
2213
|
+
) : /* @__PURE__ */ jsx35(
|
|
2101
2214
|
Input2,
|
|
2102
2215
|
{
|
|
2103
2216
|
ref: fieldRef,
|
|
@@ -2111,7 +2224,7 @@ function EditableText({ value, display, displayNode, placeholder, onCommit, mult
|
|
|
2111
2224
|
}
|
|
2112
2225
|
);
|
|
2113
2226
|
}
|
|
2114
|
-
return /* @__PURE__ */
|
|
2227
|
+
return /* @__PURE__ */ jsx35(
|
|
2115
2228
|
"button",
|
|
2116
2229
|
{
|
|
2117
2230
|
type: "button",
|
|
@@ -2130,7 +2243,7 @@ function EditableText({ value, display, displayNode, placeholder, onCommit, mult
|
|
|
2130
2243
|
|
|
2131
2244
|
// src/ProgressBar.tsx
|
|
2132
2245
|
import { Progress } from "@base-ui/react/progress";
|
|
2133
|
-
import { jsx as
|
|
2246
|
+
import { jsx as jsx36 } from "react/jsx-runtime";
|
|
2134
2247
|
var TRACK_CLASSES = {
|
|
2135
2248
|
default: "h-1.5 w-full overflow-hidden rounded-full bg-bg-inset",
|
|
2136
2249
|
// 4px, Katerina's ruling of 14 September; Peek's own bar is 3px until it takes this one.
|
|
@@ -2143,16 +2256,16 @@ var INDICATOR_CLASSES = {
|
|
|
2143
2256
|
function ProgressBar({ value, max, label, variant = "default", className }) {
|
|
2144
2257
|
return (
|
|
2145
2258
|
// `max={0}` needs no guard: Base UI reads the 0/0 share as an empty bar.
|
|
2146
|
-
/* @__PURE__ */
|
|
2259
|
+
/* @__PURE__ */ jsx36(Progress.Root, { value, max, "aria-label": label, className, children: /* @__PURE__ */ jsx36(Progress.Track, { className: TRACK_CLASSES[variant], children: /* @__PURE__ */ jsx36(Progress.Indicator, { className: INDICATOR_CLASSES[variant] }) }) })
|
|
2147
2260
|
);
|
|
2148
2261
|
}
|
|
2149
2262
|
|
|
2150
2263
|
// src/Breadcrumb.tsx
|
|
2151
|
-
import { Fragment as Fragment7, useCallback as useCallback2, useLayoutEffect as
|
|
2152
|
-
import { jsx as
|
|
2264
|
+
import { Fragment as Fragment7, useCallback as useCallback2, useLayoutEffect as useLayoutEffect4, useRef as useRef7, useState as useState6 } from "react";
|
|
2265
|
+
import { jsx as jsx37, jsxs as jsxs25 } from "react/jsx-runtime";
|
|
2153
2266
|
function Breadcrumb({ items, className }) {
|
|
2154
|
-
const navRef =
|
|
2155
|
-
const labelRefs =
|
|
2267
|
+
const navRef = useRef7(null);
|
|
2268
|
+
const labelRefs = useRef7([]);
|
|
2156
2269
|
const [truncated, setTruncated] = useState6(/* @__PURE__ */ new Set());
|
|
2157
2270
|
const measure = useCallback2(() => {
|
|
2158
2271
|
const next = /* @__PURE__ */ new Set();
|
|
@@ -2161,7 +2274,7 @@ function Breadcrumb({ items, className }) {
|
|
|
2161
2274
|
});
|
|
2162
2275
|
setTruncated((prev) => prev.size === next.size && [...next].every((i) => prev.has(i)) ? prev : next);
|
|
2163
2276
|
}, []);
|
|
2164
|
-
|
|
2277
|
+
useLayoutEffect4(() => {
|
|
2165
2278
|
measure();
|
|
2166
2279
|
const nav = navRef.current;
|
|
2167
2280
|
if (!nav || typeof ResizeObserver === "undefined") return;
|
|
@@ -2169,7 +2282,7 @@ function Breadcrumb({ items, className }) {
|
|
|
2169
2282
|
observer.observe(nav);
|
|
2170
2283
|
return () => observer.disconnect();
|
|
2171
2284
|
}, [measure, items]);
|
|
2172
|
-
return /* @__PURE__ */
|
|
2285
|
+
return /* @__PURE__ */ jsx37("nav", { ref: navRef, "aria-label": "Breadcrumb", className: cn("flex min-w-0 items-center gap-1.5 text-body-2", className), children: items.map((item, index) => {
|
|
2173
2286
|
const last = index === items.length - 1;
|
|
2174
2287
|
const tone = item.muted || last && item.mono ? "text-text-muted" : last ? "text-text-primary" : "text-text-secondary";
|
|
2175
2288
|
const text = cn(
|
|
@@ -2187,25 +2300,25 @@ function Breadcrumb({ items, className }) {
|
|
|
2187
2300
|
// `plain` adds no look of its own: a crumb keeps the trail's size and
|
|
2188
2301
|
// tone, and brightens on hover. The package's own Link, so a trail
|
|
2189
2302
|
// follows whatever a link learns to do (UIG-5).
|
|
2190
|
-
/* @__PURE__ */
|
|
2191
|
-
) : /* @__PURE__ */
|
|
2192
|
-
return /* @__PURE__ */
|
|
2193
|
-
index > 0 && /* @__PURE__ */
|
|
2194
|
-
item.icon && /* @__PURE__ */
|
|
2303
|
+
/* @__PURE__ */ jsx37(Link, { ref: setLabelRef, variant: "plain", href: item.href, onClick: item.onClick, className: cn(text, "hover:text-text-primary"), children: item.label })
|
|
2304
|
+
) : /* @__PURE__ */ jsx37("span", { ref: setLabelRef, className: text, "aria-current": last ? "page" : void 0, children: item.label });
|
|
2305
|
+
return /* @__PURE__ */ jsxs25(Fragment7, { children: [
|
|
2306
|
+
index > 0 && /* @__PURE__ */ jsx37("span", { "aria-hidden": "true", className: "shrink-0 text-text-muted", children: "/" }),
|
|
2307
|
+
item.icon && /* @__PURE__ */ jsx37("span", { "aria-hidden": "true", className: cn("flex shrink-0", tone), children: item.icon }),
|
|
2195
2308
|
truncated.has(index) ? (
|
|
2196
2309
|
// `min-w-0 shrink` undoes the wrapper's own shrink-0 — the crumb
|
|
2197
2310
|
// must keep truncating inside it, or wrapping it would widen the
|
|
2198
2311
|
// trail and the tooltip would never be needed again.
|
|
2199
|
-
/* @__PURE__ */
|
|
2312
|
+
/* @__PURE__ */ jsx37(WithTooltip, { label: item.label, wrapperClassName: "min-w-0 shrink", children: crumb })
|
|
2200
2313
|
) : crumb
|
|
2201
2314
|
] }, `${item.label}-${index}`);
|
|
2202
2315
|
}) });
|
|
2203
2316
|
}
|
|
2204
2317
|
|
|
2205
2318
|
// src/NavItem.tsx
|
|
2206
|
-
import { jsx as
|
|
2319
|
+
import { jsx as jsx38, jsxs as jsxs26 } from "react/jsx-runtime";
|
|
2207
2320
|
function NavItem({ label, href, count, countLabel, active = false, icon, className, ...props }) {
|
|
2208
|
-
return /* @__PURE__ */
|
|
2321
|
+
return /* @__PURE__ */ jsxs26(
|
|
2209
2322
|
"a",
|
|
2210
2323
|
{
|
|
2211
2324
|
href,
|
|
@@ -2220,9 +2333,9 @@ function NavItem({ label, href, count, countLabel, active = false, icon, classNa
|
|
|
2220
2333
|
),
|
|
2221
2334
|
...props,
|
|
2222
2335
|
children: [
|
|
2223
|
-
icon && /* @__PURE__ */
|
|
2224
|
-
/* @__PURE__ */
|
|
2225
|
-
count ? /* @__PURE__ */
|
|
2336
|
+
icon && /* @__PURE__ */ jsx38("span", { className: "flex shrink-0 items-center", children: icon }),
|
|
2337
|
+
/* @__PURE__ */ jsx38("span", { className: "flex-1 truncate", children: label }),
|
|
2338
|
+
count ? /* @__PURE__ */ jsx38(WithTooltip, { label: countLabel ?? `${count} open`, children: /* @__PURE__ */ jsx38("span", { className: "min-w-4 shrink-0 text-center font-mono text-caption tabular-nums text-text-muted", children: count }) }) : null
|
|
2226
2339
|
]
|
|
2227
2340
|
}
|
|
2228
2341
|
);
|
|
@@ -2231,7 +2344,7 @@ function NavItem({ label, href, count, countLabel, active = false, icon, classNa
|
|
|
2231
2344
|
// src/Popover.tsx
|
|
2232
2345
|
import { useMemo as useMemo3 } from "react";
|
|
2233
2346
|
import { Popover as BasePopover } from "@base-ui/react/popover";
|
|
2234
|
-
import { jsx as
|
|
2347
|
+
import { jsx as jsx39, jsxs as jsxs27 } from "react/jsx-runtime";
|
|
2235
2348
|
var GAP5 = 4;
|
|
2236
2349
|
var VIEWPORT_PAD5 = 8;
|
|
2237
2350
|
function Popover({ trigger, anchor, align = "left", side = "bottom", open, onOpenChange, finalFocus, actionsRef, ariaLabel, children, className, contentClassName, maxHeight }) {
|
|
@@ -2240,7 +2353,7 @@ function Popover({ trigger, anchor, align = "left", side = "bottom", open, onOpe
|
|
|
2240
2353
|
if (anchor instanceof Element) return anchor;
|
|
2241
2354
|
return { getBoundingClientRect: () => anchor };
|
|
2242
2355
|
}, [anchor]);
|
|
2243
|
-
return /* @__PURE__ */
|
|
2356
|
+
return /* @__PURE__ */ jsxs27(
|
|
2244
2357
|
BasePopover.Root,
|
|
2245
2358
|
{
|
|
2246
2359
|
open,
|
|
@@ -2248,8 +2361,8 @@ function Popover({ trigger, anchor, align = "left", side = "bottom", open, onOpe
|
|
|
2248
2361
|
actionsRef,
|
|
2249
2362
|
modal: false,
|
|
2250
2363
|
children: [
|
|
2251
|
-
trigger && /* @__PURE__ */
|
|
2252
|
-
/* @__PURE__ */
|
|
2364
|
+
trigger && /* @__PURE__ */ jsx39(BasePopover.Trigger, { render: trigger, disabled: triggerDisabled(trigger) }),
|
|
2365
|
+
/* @__PURE__ */ jsx39(BasePopover.Portal, { children: /* @__PURE__ */ jsx39(
|
|
2253
2366
|
BasePopover.Positioner,
|
|
2254
2367
|
{
|
|
2255
2368
|
anchor: anchorTarget,
|
|
@@ -2258,15 +2371,15 @@ function Popover({ trigger, anchor, align = "left", side = "bottom", open, onOpe
|
|
|
2258
2371
|
sideOffset: GAP5,
|
|
2259
2372
|
collisionPadding: VIEWPORT_PAD5,
|
|
2260
2373
|
className: "z-50 data-[anchor-hidden]:hidden",
|
|
2261
|
-
children: /* @__PURE__ */
|
|
2374
|
+
children: /* @__PURE__ */ jsx39(
|
|
2262
2375
|
BasePopover.Popup,
|
|
2263
2376
|
{
|
|
2264
2377
|
"aria-label": ariaLabel,
|
|
2265
2378
|
initialFocus: trigger ? void 0 : false,
|
|
2266
2379
|
finalFocus,
|
|
2267
2380
|
className: cn("min-w-[180px] outline-none p-0", className),
|
|
2268
|
-
render: /* @__PURE__ */
|
|
2269
|
-
children: /* @__PURE__ */
|
|
2381
|
+
render: /* @__PURE__ */ jsx39(MenuPanel, {}),
|
|
2382
|
+
children: /* @__PURE__ */ jsx39(
|
|
2270
2383
|
ScrollArea,
|
|
2271
2384
|
{
|
|
2272
2385
|
viewportClassName: maxHeight ?? "max-h-[var(--available-height)]",
|
|
@@ -2285,9 +2398,9 @@ function Popover({ trigger, anchor, align = "left", side = "bottom", open, onOpe
|
|
|
2285
2398
|
|
|
2286
2399
|
// src/Toolbar.tsx
|
|
2287
2400
|
import { Toolbar as BaseToolbar } from "@base-ui/react/toolbar";
|
|
2288
|
-
import { jsx as
|
|
2401
|
+
import { jsx as jsx40 } from "react/jsx-runtime";
|
|
2289
2402
|
function Toolbar({ "aria-label": ariaLabel, orientation = "horizontal", loopFocus = true, surface = true, children, className }) {
|
|
2290
|
-
const strip = /* @__PURE__ */
|
|
2403
|
+
const strip = /* @__PURE__ */ jsx40(
|
|
2291
2404
|
BaseToolbar.Root,
|
|
2292
2405
|
{
|
|
2293
2406
|
"aria-label": ariaLabel,
|
|
@@ -2298,24 +2411,24 @@ function Toolbar({ "aria-label": ariaLabel, orientation = "horizontal", loopFocu
|
|
|
2298
2411
|
}
|
|
2299
2412
|
);
|
|
2300
2413
|
if (!surface) return strip;
|
|
2301
|
-
return /* @__PURE__ */
|
|
2414
|
+
return /* @__PURE__ */ jsx40(MenuPanel, { className: "w-fit p-1", children: strip });
|
|
2302
2415
|
}
|
|
2303
2416
|
function ToolbarButton({ ref, disabled, disabledReason, ...props }) {
|
|
2304
|
-
return /* @__PURE__ */
|
|
2417
|
+
return /* @__PURE__ */ jsx40(
|
|
2305
2418
|
BaseToolbar.Button,
|
|
2306
2419
|
{
|
|
2307
2420
|
ref,
|
|
2308
2421
|
disabled: disabled || !!disabledReason,
|
|
2309
2422
|
focusableWhenDisabled: true,
|
|
2310
|
-
render: /* @__PURE__ */
|
|
2423
|
+
render: /* @__PURE__ */ jsx40(IconButton, { disabled, disabledReason, ...props })
|
|
2311
2424
|
}
|
|
2312
2425
|
);
|
|
2313
2426
|
}
|
|
2314
2427
|
function ToolbarInput({ size, ...props }) {
|
|
2315
|
-
return /* @__PURE__ */
|
|
2428
|
+
return /* @__PURE__ */ jsx40(BaseToolbar.Input, { render: /* @__PURE__ */ jsx40(TextInput, { size }), ...props });
|
|
2316
2429
|
}
|
|
2317
2430
|
function ToolbarSeparator({ className }) {
|
|
2318
|
-
return /* @__PURE__ */
|
|
2431
|
+
return /* @__PURE__ */ jsx40(
|
|
2319
2432
|
BaseToolbar.Separator,
|
|
2320
2433
|
{
|
|
2321
2434
|
orientation: "vertical",
|
|
@@ -2325,9 +2438,9 @@ function ToolbarSeparator({ className }) {
|
|
|
2325
2438
|
}
|
|
2326
2439
|
|
|
2327
2440
|
// src/ReactionPicker.tsx
|
|
2328
|
-
import { jsx as
|
|
2441
|
+
import { jsx as jsx41 } from "react/jsx-runtime";
|
|
2329
2442
|
function ReactionPicker({ options, onSelect, "aria-label": ariaLabel = "Reactions", surface = true, className }) {
|
|
2330
|
-
return /* @__PURE__ */
|
|
2443
|
+
return /* @__PURE__ */ jsx41(Toolbar, { "aria-label": ariaLabel, surface, className: cn("gap-0.5", className), children: options.map((option) => (
|
|
2331
2444
|
/*
|
|
2332
2445
|
A `ToolbarButton`, not a button in a tooltip wrapper. The wrapper
|
|
2333
2446
|
would become the toolbar's item and the button inside it would never
|
|
@@ -2337,14 +2450,14 @@ function ReactionPicker({ options, onSelect, "aria-label": ariaLabel = "Reaction
|
|
|
2337
2450
|
The tooltip names it for a pointer, `aria-label` for everything else,
|
|
2338
2451
|
and both say the meaning rather than the glyph.
|
|
2339
2452
|
*/
|
|
2340
|
-
/* @__PURE__ */
|
|
2453
|
+
/* @__PURE__ */ jsx41(
|
|
2341
2454
|
ToolbarButton,
|
|
2342
2455
|
{
|
|
2343
2456
|
"aria-label": option.label,
|
|
2344
2457
|
tooltip: option.label,
|
|
2345
2458
|
onClick: () => onSelect(option.emoji),
|
|
2346
2459
|
className: "size-7 text-h3 leading-none",
|
|
2347
|
-
children: /* @__PURE__ */
|
|
2460
|
+
children: /* @__PURE__ */ jsx41("span", { "aria-hidden": "true", children: option.emoji })
|
|
2348
2461
|
},
|
|
2349
2462
|
option.emoji
|
|
2350
2463
|
)
|
|
@@ -2353,23 +2466,23 @@ function ReactionPicker({ options, onSelect, "aria-label": ariaLabel = "Reaction
|
|
|
2353
2466
|
|
|
2354
2467
|
// src/PreviewCard.tsx
|
|
2355
2468
|
import { PreviewCard as BasePreviewCard } from "@base-ui/react/preview-card";
|
|
2356
|
-
import { jsx as
|
|
2469
|
+
import { jsx as jsx42, jsxs as jsxs28 } from "react/jsx-runtime";
|
|
2357
2470
|
var GAP6 = 12;
|
|
2358
2471
|
var VIEWPORT_PAD6 = 8;
|
|
2359
2472
|
var OPEN_DELAY2 = 350;
|
|
2360
2473
|
var CLOSE_DELAY = 200;
|
|
2361
2474
|
function PreviewCard({ content, children, side = "right", delay = OPEN_DELAY2, closeDelay = CLOSE_DELAY, className, wrapperClassName }) {
|
|
2362
|
-
return /* @__PURE__ */
|
|
2363
|
-
/* @__PURE__ */
|
|
2475
|
+
return /* @__PURE__ */ jsxs28(BasePreviewCard.Root, { children: [
|
|
2476
|
+
/* @__PURE__ */ jsx42(
|
|
2364
2477
|
BasePreviewCard.Trigger,
|
|
2365
2478
|
{
|
|
2366
2479
|
delay,
|
|
2367
2480
|
closeDelay,
|
|
2368
|
-
render: /* @__PURE__ */
|
|
2481
|
+
render: /* @__PURE__ */ jsx42("span", { className: cn("inline-flex", wrapperClassName) }),
|
|
2369
2482
|
children
|
|
2370
2483
|
}
|
|
2371
2484
|
),
|
|
2372
|
-
/* @__PURE__ */
|
|
2485
|
+
/* @__PURE__ */ jsx42(BasePreviewCard.Portal, { children: /* @__PURE__ */ jsx42(
|
|
2373
2486
|
BasePreviewCard.Positioner,
|
|
2374
2487
|
{
|
|
2375
2488
|
side,
|
|
@@ -2377,12 +2490,12 @@ function PreviewCard({ content, children, side = "right", delay = OPEN_DELAY2, c
|
|
|
2377
2490
|
sideOffset: GAP6,
|
|
2378
2491
|
collisionPadding: VIEWPORT_PAD6,
|
|
2379
2492
|
className: "z-50 data-[anchor-hidden]:hidden",
|
|
2380
|
-
children: /* @__PURE__ */
|
|
2493
|
+
children: /* @__PURE__ */ jsx42(
|
|
2381
2494
|
BasePreviewCard.Popup,
|
|
2382
2495
|
{
|
|
2383
2496
|
className: cn("w-[360px] p-3 outline-none", className),
|
|
2384
|
-
render: /* @__PURE__ */
|
|
2385
|
-
children: /* @__PURE__ */
|
|
2497
|
+
render: /* @__PURE__ */ jsx42(MenuPanel, {}),
|
|
2498
|
+
children: /* @__PURE__ */ jsx42(ScrollArea, { viewportClassName: "max-h-[calc(min(300px,var(--available-height))_-_1.5rem)]", contentClassName: "flex flex-col gap-3 [&>*]:shrink-0", children: content })
|
|
2386
2499
|
}
|
|
2387
2500
|
)
|
|
2388
2501
|
}
|
|
@@ -2391,15 +2504,15 @@ function PreviewCard({ content, children, side = "right", delay = OPEN_DELAY2, c
|
|
|
2391
2504
|
}
|
|
2392
2505
|
|
|
2393
2506
|
// src/Rail.tsx
|
|
2394
|
-
import { jsx as
|
|
2507
|
+
import { jsx as jsx43 } from "react/jsx-runtime";
|
|
2395
2508
|
function Rail({ "aria-label": ariaLabel = "Navigation", children, className }) {
|
|
2396
|
-
return /* @__PURE__ */
|
|
2509
|
+
return /* @__PURE__ */ jsx43("nav", { "aria-label": ariaLabel, className: cn("flex w-16 shrink-0 flex-col items-start gap-2 px-2 py-3", className), children });
|
|
2397
2510
|
}
|
|
2398
2511
|
|
|
2399
2512
|
// src/RailItem.tsx
|
|
2400
|
-
import { jsx as
|
|
2513
|
+
import { jsx as jsx44, jsxs as jsxs29 } from "react/jsx-runtime";
|
|
2401
2514
|
function RailItem({ href, icon, label, active = false, className, ...props }) {
|
|
2402
|
-
return /* @__PURE__ */
|
|
2515
|
+
return /* @__PURE__ */ jsxs29(
|
|
2403
2516
|
"a",
|
|
2404
2517
|
{
|
|
2405
2518
|
href,
|
|
@@ -2407,14 +2520,14 @@ function RailItem({ href, icon, label, active = false, className, ...props }) {
|
|
|
2407
2520
|
className: cn("group flex w-full shrink-0 flex-col items-center gap-0.5 px-2 py-0.5", className),
|
|
2408
2521
|
...props,
|
|
2409
2522
|
children: [
|
|
2410
|
-
/* @__PURE__ */
|
|
2523
|
+
/* @__PURE__ */ jsx44(
|
|
2411
2524
|
"div",
|
|
2412
2525
|
{
|
|
2413
2526
|
className: cn(
|
|
2414
2527
|
"flex items-center justify-center rounded-lg p-2 transition-colors",
|
|
2415
2528
|
active ? "bg-bg-selected" : "group-hover:bg-bg-hover"
|
|
2416
2529
|
),
|
|
2417
|
-
children: /* @__PURE__ */
|
|
2530
|
+
children: /* @__PURE__ */ jsx44(
|
|
2418
2531
|
"span",
|
|
2419
2532
|
{
|
|
2420
2533
|
className: cn(
|
|
@@ -2426,27 +2539,27 @@ function RailItem({ href, icon, label, active = false, className, ...props }) {
|
|
|
2426
2539
|
)
|
|
2427
2540
|
}
|
|
2428
2541
|
),
|
|
2429
|
-
/* @__PURE__ */
|
|
2542
|
+
/* @__PURE__ */ jsx44("span", { className: cn("text-center text-menu", active ? "text-text-primary" : "text-text-secondary"), children: label })
|
|
2430
2543
|
]
|
|
2431
2544
|
}
|
|
2432
2545
|
);
|
|
2433
2546
|
}
|
|
2434
2547
|
|
|
2435
2548
|
// src/Sidebar.tsx
|
|
2436
|
-
import { jsx as
|
|
2549
|
+
import { jsx as jsx45 } from "react/jsx-runtime";
|
|
2437
2550
|
function Sidebar({ "aria-label": ariaLabel = "Workspace", children, className }) {
|
|
2438
|
-
return /* @__PURE__ */
|
|
2551
|
+
return /* @__PURE__ */ jsx45(
|
|
2439
2552
|
"nav",
|
|
2440
2553
|
{
|
|
2441
2554
|
"aria-label": ariaLabel,
|
|
2442
2555
|
className: cn("flex w-60 shrink-0 flex-col border-r border-border-default bg-bg-surface", className),
|
|
2443
|
-
children: /* @__PURE__ */
|
|
2556
|
+
children: /* @__PURE__ */ jsx45(ScrollArea, { className: "min-h-0 flex-1", contentClassName: "flex flex-col gap-px px-2.5 py-3", children })
|
|
2444
2557
|
}
|
|
2445
2558
|
);
|
|
2446
2559
|
}
|
|
2447
2560
|
|
|
2448
2561
|
// src/Property.tsx
|
|
2449
|
-
import { jsx as
|
|
2562
|
+
import { jsx as jsx46, jsxs as jsxs30 } from "react/jsx-runtime";
|
|
2450
2563
|
var VALUE_CLASSES = "contents";
|
|
2451
2564
|
function Property({ label, layout = "row", children, className }) {
|
|
2452
2565
|
if (layout === "stacked") {
|
|
@@ -2454,23 +2567,23 @@ function Property({ label, layout = "row", children, className }) {
|
|
|
2454
2567
|
// gap-3 — the one label-above-content distance (Katerina, 2026-09-01):
|
|
2455
2568
|
// Peek's topic-details sections already sit at 12px, Ship's rail was
|
|
2456
2569
|
// 6px, and unifying means the bigger, calmer one.
|
|
2457
|
-
/* @__PURE__ */
|
|
2458
|
-
/* @__PURE__ */
|
|
2459
|
-
/* @__PURE__ */
|
|
2570
|
+
/* @__PURE__ */ jsxs30("dl", { className: cn("flex flex-col gap-3", className), children: [
|
|
2571
|
+
/* @__PURE__ */ jsx46("dt", { className: "text-menu uppercase tracking-widest text-text-secondary", children: label }),
|
|
2572
|
+
/* @__PURE__ */ jsx46("dd", { className: VALUE_CLASSES, children })
|
|
2460
2573
|
] })
|
|
2461
2574
|
);
|
|
2462
2575
|
}
|
|
2463
|
-
return /* @__PURE__ */
|
|
2464
|
-
/* @__PURE__ */
|
|
2465
|
-
/* @__PURE__ */
|
|
2576
|
+
return /* @__PURE__ */ jsxs30("dl", { className: cn("flex items-center gap-2", className), children: [
|
|
2577
|
+
/* @__PURE__ */ jsx46("dt", { className: "w-[68px] shrink-0 text-caption text-text-secondary", children: label }),
|
|
2578
|
+
/* @__PURE__ */ jsx46("dd", { className: VALUE_CLASSES, children })
|
|
2466
2579
|
] });
|
|
2467
2580
|
}
|
|
2468
2581
|
|
|
2469
2582
|
// src/Reaction.tsx
|
|
2470
2583
|
import { Toggle } from "@base-ui/react/toggle";
|
|
2471
|
-
import { jsx as
|
|
2584
|
+
import { jsx as jsx47, jsxs as jsxs31 } from "react/jsx-runtime";
|
|
2472
2585
|
function Reaction({ emoji, count, pressed = false, className, ...props }) {
|
|
2473
|
-
return /* @__PURE__ */
|
|
2586
|
+
return /* @__PURE__ */ jsxs31(
|
|
2474
2587
|
Toggle,
|
|
2475
2588
|
{
|
|
2476
2589
|
pressed,
|
|
@@ -2492,8 +2605,8 @@ function Reaction({ emoji, count, pressed = false, className, ...props }) {
|
|
|
2492
2605
|
),
|
|
2493
2606
|
...props,
|
|
2494
2607
|
children: [
|
|
2495
|
-
/* @__PURE__ */
|
|
2496
|
-
/* @__PURE__ */
|
|
2608
|
+
/* @__PURE__ */ jsx47("span", { "aria-hidden": "true", className: "shrink-0 text-body-1 leading-none", children: emoji }),
|
|
2609
|
+
/* @__PURE__ */ jsx47("span", { className: "text-chip signal:font-mono signal:text-small signal:font-semibold signal:tabular-nums", children: count })
|
|
2497
2610
|
]
|
|
2498
2611
|
}
|
|
2499
2612
|
);
|
|
@@ -2502,19 +2615,21 @@ function Reaction({ emoji, count, pressed = false, className, ...props }) {
|
|
|
2502
2615
|
// src/SearchInput.tsx
|
|
2503
2616
|
import "react";
|
|
2504
2617
|
import { Input as Input3 } from "@base-ui/react/input";
|
|
2505
|
-
import { jsx as
|
|
2618
|
+
import { jsx as jsx48, jsxs as jsxs32 } from "react/jsx-runtime";
|
|
2506
2619
|
function SearchInput({ shortcut, className, placeholder = "Search\u2026", ...props }) {
|
|
2507
|
-
return /* @__PURE__ */
|
|
2620
|
+
return /* @__PURE__ */ jsxs32(
|
|
2508
2621
|
"div",
|
|
2509
2622
|
{
|
|
2510
2623
|
className: cn(
|
|
2511
2624
|
"flex gap-2 items-center px-3 py-2 rounded-lg",
|
|
2512
2625
|
"bg-bg-inset border border-border-default",
|
|
2513
|
-
|
|
2626
|
+
// Hover strengthens the border as it does on every other field (16 September). Here that
|
|
2627
|
+
// is also the focus look, which was the stronger border before hover existed.
|
|
2628
|
+
"hover:border-border-strong focus-within:border-border-strong transition-colors",
|
|
2514
2629
|
className
|
|
2515
2630
|
),
|
|
2516
2631
|
children: [
|
|
2517
|
-
/* @__PURE__ */
|
|
2632
|
+
/* @__PURE__ */ jsx48(
|
|
2518
2633
|
Input3,
|
|
2519
2634
|
{
|
|
2520
2635
|
className: "flex-1 min-w-0 bg-transparent text-input-value text-text-primary placeholder:text-text-muted outline-none",
|
|
@@ -2522,7 +2637,7 @@ function SearchInput({ shortcut, className, placeholder = "Search\u2026", ...pro
|
|
|
2522
2637
|
...props
|
|
2523
2638
|
}
|
|
2524
2639
|
),
|
|
2525
|
-
shortcut && /* @__PURE__ */
|
|
2640
|
+
shortcut && /* @__PURE__ */ jsx48(Kbd, { children: shortcut })
|
|
2526
2641
|
]
|
|
2527
2642
|
}
|
|
2528
2643
|
);
|
|
@@ -2531,17 +2646,17 @@ function SearchInput({ shortcut, className, placeholder = "Search\u2026", ...pro
|
|
|
2531
2646
|
// src/SectionHeader.tsx
|
|
2532
2647
|
import { IconChevronRight as IconChevronRight2 } from "@tabler/icons-react";
|
|
2533
2648
|
import { useRender } from "@base-ui/react/use-render";
|
|
2534
|
-
import { Fragment as Fragment8, jsx as
|
|
2649
|
+
import { Fragment as Fragment8, jsx as jsx49, jsxs as jsxs33 } from "react/jsx-runtime";
|
|
2535
2650
|
function SectionHeader({ title, chevron = false, isExpanded = true, onToggle, trailing, actions, showActions = "hover", render, className }) {
|
|
2536
2651
|
const titleElement = useRender({
|
|
2537
|
-
render: render ?? (chevron ? /* @__PURE__ */
|
|
2652
|
+
render: render ?? (chevron ? /* @__PURE__ */ jsx49("button", { type: "button", onClick: onToggle, "aria-expanded": isExpanded }) : /* @__PURE__ */ jsx49("span", {})),
|
|
2538
2653
|
props: {
|
|
2539
2654
|
// `text-left`: a button centres its text. `h-full` and `flex-1`: the
|
|
2540
2655
|
// whole row up to the actions is the hit target, as it was when the
|
|
2541
2656
|
// row itself carried the click.
|
|
2542
2657
|
className: "flex h-full min-w-0 flex-1 items-center gap-1 text-left",
|
|
2543
|
-
children: /* @__PURE__ */
|
|
2544
|
-
chevron && /* @__PURE__ */
|
|
2658
|
+
children: /* @__PURE__ */ jsxs33(Fragment8, { children: [
|
|
2659
|
+
chevron && /* @__PURE__ */ jsx49(
|
|
2545
2660
|
IconChevronRight2,
|
|
2546
2661
|
{
|
|
2547
2662
|
size: 12,
|
|
@@ -2549,11 +2664,11 @@ function SectionHeader({ title, chevron = false, isExpanded = true, onToggle, tr
|
|
|
2549
2664
|
className: cn("shrink-0 text-text-secondary transition-transform duration-150", isExpanded && "rotate-90")
|
|
2550
2665
|
}
|
|
2551
2666
|
),
|
|
2552
|
-
/* @__PURE__ */
|
|
2667
|
+
/* @__PURE__ */ jsx49(SectionLabel, { children: title })
|
|
2553
2668
|
] })
|
|
2554
2669
|
}
|
|
2555
2670
|
});
|
|
2556
|
-
return /* @__PURE__ */
|
|
2671
|
+
return /* @__PURE__ */ jsxs33(
|
|
2557
2672
|
"div",
|
|
2558
2673
|
{
|
|
2559
2674
|
className: cn(
|
|
@@ -2566,15 +2681,15 @@ function SectionHeader({ title, chevron = false, isExpanded = true, onToggle, tr
|
|
|
2566
2681
|
),
|
|
2567
2682
|
children: [
|
|
2568
2683
|
titleElement,
|
|
2569
|
-
trailing != null && /* @__PURE__ */
|
|
2570
|
-
actions && actions.length > 0 && /* @__PURE__ */
|
|
2684
|
+
trailing != null && /* @__PURE__ */ jsx49("div", { className: "flex shrink-0 items-center", children: trailing }),
|
|
2685
|
+
actions && actions.length > 0 && /* @__PURE__ */ jsx49(
|
|
2571
2686
|
"div",
|
|
2572
2687
|
{
|
|
2573
2688
|
className: cn(
|
|
2574
2689
|
"-mr-1 flex shrink-0 items-center gap-1",
|
|
2575
2690
|
showActions === "hover" && "opacity-0 transition-opacity focus-within:opacity-100 group-hover:opacity-100"
|
|
2576
2691
|
),
|
|
2577
|
-
children: actions.map((action) => /* @__PURE__ */
|
|
2692
|
+
children: actions.map((action) => /* @__PURE__ */ jsx49(IconButton, { tooltip: action.tooltip, "aria-label": action.tooltip, onClick: action.onClick, children: action.icon }, action.tooltip))
|
|
2578
2693
|
}
|
|
2579
2694
|
)
|
|
2580
2695
|
]
|
|
@@ -2585,7 +2700,7 @@ function SectionHeader({ title, chevron = false, isExpanded = true, onToggle, tr
|
|
|
2585
2700
|
// src/CollapsibleSection.tsx
|
|
2586
2701
|
import { useState as useState7 } from "react";
|
|
2587
2702
|
import { Collapsible } from "@base-ui/react/collapsible";
|
|
2588
|
-
import { jsx as
|
|
2703
|
+
import { jsx as jsx50, jsxs as jsxs34 } from "react/jsx-runtime";
|
|
2589
2704
|
var OPEN = "open";
|
|
2590
2705
|
var CLOSED = "closed";
|
|
2591
2706
|
function readStored(key) {
|
|
@@ -2612,14 +2727,14 @@ function CollapsibleSection({ title, defaultOpen = true, open: openProp, onOpenC
|
|
|
2612
2727
|
writeStored(storageKey, next);
|
|
2613
2728
|
onOpenChange?.(next);
|
|
2614
2729
|
};
|
|
2615
|
-
return /* @__PURE__ */
|
|
2616
|
-
/* @__PURE__ */
|
|
2617
|
-
/* @__PURE__ */
|
|
2730
|
+
return /* @__PURE__ */ jsxs34(Collapsible.Root, { open, onOpenChange: setOpen, className: cn("flex flex-col", className), children: [
|
|
2731
|
+
/* @__PURE__ */ jsx50(SectionHeader, { title, chevron: true, isExpanded: open, trailing, actions, showActions, className: "shrink-0", render: /* @__PURE__ */ jsx50(Collapsible.Trigger, {}) }),
|
|
2732
|
+
/* @__PURE__ */ jsx50(
|
|
2618
2733
|
Collapsible.Panel,
|
|
2619
2734
|
{
|
|
2620
2735
|
hiddenUntilFound: true,
|
|
2621
2736
|
className: "h-[var(--collapsible-panel-height)] overflow-hidden transition-[height] duration-150 ease-out motion-reduce:transition-none data-[starting-style]:h-0 data-[ending-style]:h-0",
|
|
2622
|
-
children: /* @__PURE__ */
|
|
2737
|
+
children: /* @__PURE__ */ jsx50("div", { className: cn("flex flex-col", contentClassName), children })
|
|
2623
2738
|
}
|
|
2624
2739
|
)
|
|
2625
2740
|
] });
|
|
@@ -2627,9 +2742,9 @@ function CollapsibleSection({ title, defaultOpen = true, open: openProp, onOpenC
|
|
|
2627
2742
|
|
|
2628
2743
|
// src/Tabs.tsx
|
|
2629
2744
|
import { Tabs as BaseTabs } from "@base-ui/react/tabs";
|
|
2630
|
-
import { jsx as
|
|
2745
|
+
import { jsx as jsx51, jsxs as jsxs35 } from "react/jsx-runtime";
|
|
2631
2746
|
function Tabs({ tabs, active, onChange, size = "default", className, ...aria }) {
|
|
2632
|
-
return /* @__PURE__ */
|
|
2747
|
+
return /* @__PURE__ */ jsx51(
|
|
2633
2748
|
BaseTabs.Root,
|
|
2634
2749
|
{
|
|
2635
2750
|
value: active,
|
|
@@ -2637,14 +2752,14 @@ function Tabs({ tabs, active, onChange, size = "default", className, ...aria })
|
|
|
2637
2752
|
if (details.reason === "none") onChange(value);
|
|
2638
2753
|
},
|
|
2639
2754
|
className,
|
|
2640
|
-
children: /* @__PURE__ */
|
|
2755
|
+
children: /* @__PURE__ */ jsx51(
|
|
2641
2756
|
BaseTabs.List,
|
|
2642
2757
|
{
|
|
2643
2758
|
activateOnFocus: true,
|
|
2644
2759
|
"aria-label": aria["aria-label"],
|
|
2645
2760
|
"aria-labelledby": aria["aria-labelledby"],
|
|
2646
2761
|
className: "flex items-center gap-2",
|
|
2647
|
-
children: tabs.map((tab) => /* @__PURE__ */
|
|
2762
|
+
children: tabs.map((tab) => /* @__PURE__ */ jsxs35(
|
|
2648
2763
|
BaseTabs.Tab,
|
|
2649
2764
|
{
|
|
2650
2765
|
value: tab.id,
|
|
@@ -2657,9 +2772,9 @@ function Tabs({ tabs, active, onChange, size = "default", className, ...aria })
|
|
|
2657
2772
|
),
|
|
2658
2773
|
children: [
|
|
2659
2774
|
tab.icon,
|
|
2660
|
-
/* @__PURE__ */
|
|
2775
|
+
/* @__PURE__ */ jsxs35("span", { className: "flex items-baseline", children: [
|
|
2661
2776
|
tab.label,
|
|
2662
|
-
tab.count !== void 0 ? /* @__PURE__ */
|
|
2777
|
+
tab.count !== void 0 ? /* @__PURE__ */ jsx51("span", { className: "ml-2.5 font-mono text-caption tabular-nums text-text-secondary", children: tab.count }) : null
|
|
2663
2778
|
] })
|
|
2664
2779
|
]
|
|
2665
2780
|
},
|
|
@@ -2672,10 +2787,10 @@ function Tabs({ tabs, active, onChange, size = "default", className, ...aria })
|
|
|
2672
2787
|
}
|
|
2673
2788
|
|
|
2674
2789
|
// src/Toast.tsx
|
|
2675
|
-
import { createContext as
|
|
2790
|
+
import { createContext as createContext4, useContext as useContext4, useMemo as useMemo4 } from "react";
|
|
2676
2791
|
import { Toast as BaseToast } from "@base-ui/react/toast";
|
|
2677
2792
|
import { IconAlertCircle as IconAlertCircle2, IconCircleCheck, IconCircleX } from "@tabler/icons-react";
|
|
2678
|
-
import { jsx as
|
|
2793
|
+
import { jsx as jsx52, jsxs as jsxs36 } from "react/jsx-runtime";
|
|
2679
2794
|
var SURFACE_STYLES = {
|
|
2680
2795
|
success: "bg-success-muted signal:bg-bg-inset signal:border signal:border-border-default signal:shadow-md",
|
|
2681
2796
|
brand: "bg-accent-muted signal:bg-bg-inset signal:border signal:border-border-default signal:shadow-md",
|
|
@@ -2711,19 +2826,19 @@ var pillClassName = (type, hasAction, className) => cn(
|
|
|
2711
2826
|
);
|
|
2712
2827
|
function LeadingIcon({ type }) {
|
|
2713
2828
|
const Icon = ICONS[type];
|
|
2714
|
-
return /* @__PURE__ */
|
|
2829
|
+
return /* @__PURE__ */ jsx52(Icon, { size: 16, stroke: 1.5, className: cn("text-text-primary shrink-0", ICON_STYLES[type]) });
|
|
2715
2830
|
}
|
|
2716
2831
|
function Toast({ label, type = "neutral", leadingIcon = true, actionLabel, onAction, className }) {
|
|
2717
2832
|
const hasAction = !!(actionLabel && onAction);
|
|
2718
|
-
return /* @__PURE__ */
|
|
2719
|
-
/* @__PURE__ */
|
|
2720
|
-
leadingIcon && /* @__PURE__ */
|
|
2721
|
-
/* @__PURE__ */
|
|
2833
|
+
return /* @__PURE__ */ jsxs36("div", { className: pillClassName(type, hasAction, className), children: [
|
|
2834
|
+
/* @__PURE__ */ jsxs36("div", { className: "flex items-center gap-2 shrink-0", children: [
|
|
2835
|
+
leadingIcon && /* @__PURE__ */ jsx52(LeadingIcon, { type }),
|
|
2836
|
+
/* @__PURE__ */ jsx52("span", { className: LABEL_CLASSES, children: label })
|
|
2722
2837
|
] }),
|
|
2723
|
-
hasAction && /* @__PURE__ */
|
|
2838
|
+
hasAction && /* @__PURE__ */ jsx52(Button, { variant: "outlined", size: "small", onClick: onAction, children: actionLabel })
|
|
2724
2839
|
] });
|
|
2725
2840
|
}
|
|
2726
|
-
var ToastContext =
|
|
2841
|
+
var ToastContext = createContext4(null);
|
|
2727
2842
|
var VISIBLE_TOASTS = 3;
|
|
2728
2843
|
function ToastProvider({ children }) {
|
|
2729
2844
|
const manager = useMemo4(() => BaseToast.createToastManager(), []);
|
|
@@ -2741,9 +2856,9 @@ function ToastProvider({ children }) {
|
|
|
2741
2856
|
}),
|
|
2742
2857
|
[manager]
|
|
2743
2858
|
);
|
|
2744
|
-
return /* @__PURE__ */
|
|
2859
|
+
return /* @__PURE__ */ jsx52(ToastContext.Provider, { value, children: /* @__PURE__ */ jsxs36(BaseToast.Provider, { toastManager: manager, limit: VISIBLE_TOASTS, children: [
|
|
2745
2860
|
children,
|
|
2746
|
-
/* @__PURE__ */
|
|
2861
|
+
/* @__PURE__ */ jsx52(BaseToast.Portal, { children: /* @__PURE__ */ jsx52(BaseToast.Viewport, { className: "fixed bottom-4 left-4 z-[100] flex flex-col-reverse items-start gap-2 pointer-events-none", children: /* @__PURE__ */ jsx52(ToastList, {}) }) })
|
|
2747
2862
|
] }) });
|
|
2748
2863
|
}
|
|
2749
2864
|
function ToastList() {
|
|
@@ -2751,25 +2866,25 @@ function ToastList() {
|
|
|
2751
2866
|
return toasts.map((toast) => {
|
|
2752
2867
|
const type = toast.type ?? "neutral";
|
|
2753
2868
|
const { leadingIcon = true, actionLabel, onAction } = toast.data ?? {};
|
|
2754
|
-
return /* @__PURE__ */
|
|
2869
|
+
return /* @__PURE__ */ jsxs36(
|
|
2755
2870
|
BaseToast.Root,
|
|
2756
2871
|
{
|
|
2757
2872
|
toast,
|
|
2758
2873
|
swipeDirection: ["left", "down"],
|
|
2759
2874
|
className: pillClassName(type, !!actionLabel, "pointer-events-auto data-[limited]:hidden"),
|
|
2760
2875
|
children: [
|
|
2761
|
-
/* @__PURE__ */
|
|
2762
|
-
leadingIcon && /* @__PURE__ */
|
|
2763
|
-
/* @__PURE__ */
|
|
2876
|
+
/* @__PURE__ */ jsxs36("div", { className: "flex items-center gap-2 shrink-0", children: [
|
|
2877
|
+
leadingIcon && /* @__PURE__ */ jsx52(LeadingIcon, { type }),
|
|
2878
|
+
/* @__PURE__ */ jsx52(BaseToast.Title, { render: /* @__PURE__ */ jsx52("span", {}), className: LABEL_CLASSES })
|
|
2764
2879
|
] }),
|
|
2765
|
-
actionLabel && /* @__PURE__ */
|
|
2880
|
+
actionLabel && /* @__PURE__ */ jsx52(
|
|
2766
2881
|
BaseToast.Action,
|
|
2767
2882
|
{
|
|
2768
2883
|
onClick: () => {
|
|
2769
2884
|
onAction?.();
|
|
2770
2885
|
close(toast.id);
|
|
2771
2886
|
},
|
|
2772
|
-
render: /* @__PURE__ */
|
|
2887
|
+
render: /* @__PURE__ */ jsx52(Button, { variant: "outlined", size: "small", children: actionLabel })
|
|
2773
2888
|
}
|
|
2774
2889
|
)
|
|
2775
2890
|
]
|
|
@@ -2779,7 +2894,7 @@ function ToastList() {
|
|
|
2779
2894
|
});
|
|
2780
2895
|
}
|
|
2781
2896
|
function useToast() {
|
|
2782
|
-
const ctx =
|
|
2897
|
+
const ctx = useContext4(ToastContext);
|
|
2783
2898
|
if (!ctx) throw new Error("useToast must be used within ToastProvider");
|
|
2784
2899
|
return ctx;
|
|
2785
2900
|
}
|
|
@@ -2810,6 +2925,8 @@ export {
|
|
|
2810
2925
|
EnterHint,
|
|
2811
2926
|
Field,
|
|
2812
2927
|
FieldLine,
|
|
2928
|
+
FilePicker,
|
|
2929
|
+
Form,
|
|
2813
2930
|
INLINE_CHIP_CLASSES,
|
|
2814
2931
|
INLINE_CHIP_TONE_CLASSES,
|
|
2815
2932
|
IconButton,
|