@estiva-app/ui 0.16.0 → 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/CommandPalette.d.ts +8 -1
- package/dist/CommandPalette.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 +363 -241
- 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/CommandPalette.mdx +11 -5
- package/src/CommandPalette.stories.tsx +3 -1
- package/src/CommandPalette.test.tsx +24 -1
- package/src/CommandPalette.tsx +23 -2
- 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
|
|
@@ -1314,7 +1337,7 @@ function Footer({ keys }) {
|
|
|
1314
1337
|
] });
|
|
1315
1338
|
}
|
|
1316
1339
|
var lowerFirst = (s) => s.charAt(0).toLowerCase() + s.slice(1);
|
|
1317
|
-
function CommandPaletteSearch({ query, onQueryChange, placeholder, groups, chip, pending, empty, children }) {
|
|
1340
|
+
function CommandPaletteSearch({ query, onQueryChange, placeholder, groups, chip, pending, notes = [], empty, children }) {
|
|
1318
1341
|
const { modKey, popupRef } = usePalette("CommandPaletteSearch");
|
|
1319
1342
|
const back = useBack(chip, popupRef);
|
|
1320
1343
|
const items = useMemo2(() => groups.filter((g) => g.rows.length > 0).map((g) => ({ value: g.label, items: g.rows })), [groups]);
|
|
@@ -1324,10 +1347,13 @@ function CommandPaletteSearch({ query, onQueryChange, placeholder, groups, chip,
|
|
|
1324
1347
|
const inputRef = useRef2(null);
|
|
1325
1348
|
const reported = useRef2({});
|
|
1326
1349
|
const settled = useRef2(null);
|
|
1350
|
+
const moved = useRef2(false);
|
|
1327
1351
|
useLayoutEffect2(() => {
|
|
1328
1352
|
const before = settled.current;
|
|
1329
1353
|
const now = reported.current;
|
|
1330
|
-
|
|
1354
|
+
const sameLevel = before?.query === query && before?.level === chip?.label;
|
|
1355
|
+
if (!sameLevel) moved.current = false;
|
|
1356
|
+
if (moved.current && before?.id && now.reason === "none" && now.id !== before.id && sameLevel) {
|
|
1331
1357
|
const ids = rows.map((r) => r.id);
|
|
1332
1358
|
const want = ids.indexOf(before.id);
|
|
1333
1359
|
const at = now.id === void 0 ? -1 : ids.indexOf(now.id);
|
|
@@ -1381,7 +1407,7 @@ function CommandPaletteSearch({ query, onQueryChange, placeholder, groups, chip,
|
|
|
1381
1407
|
...chip && query === "" ? [["Backspace", "back"]] : [],
|
|
1382
1408
|
["Esc", "close"]
|
|
1383
1409
|
];
|
|
1384
|
-
return /* @__PURE__ */
|
|
1410
|
+
return /* @__PURE__ */ jsxs16(
|
|
1385
1411
|
Autocomplete.Root,
|
|
1386
1412
|
{
|
|
1387
1413
|
items,
|
|
@@ -1400,10 +1426,11 @@ function CommandPaletteSearch({ query, onQueryChange, placeholder, groups, chip,
|
|
|
1400
1426
|
onItemHighlighted: (row, details) => {
|
|
1401
1427
|
const id = row?.id;
|
|
1402
1428
|
reported.current = { id, reason: details.reason };
|
|
1429
|
+
if (details.reason !== "none") moved.current = true;
|
|
1403
1430
|
setLitId(id);
|
|
1404
1431
|
},
|
|
1405
1432
|
children: [
|
|
1406
|
-
/* @__PURE__ */
|
|
1433
|
+
/* @__PURE__ */ jsxs16("div", { className: "flex h-12 shrink-0 items-center gap-3 border-b border-border-subtle px-5", children: [
|
|
1407
1434
|
/* @__PURE__ */ jsx22(IconSearch, { size: 16, stroke: 1.5, className: "shrink-0 text-text-secondary" }),
|
|
1408
1435
|
chip && /* @__PURE__ */ jsx22(LevelChip, { chip, onBack: back }),
|
|
1409
1436
|
/* @__PURE__ */ jsx22(
|
|
@@ -1418,9 +1445,9 @@ function CommandPaletteSearch({ query, onQueryChange, placeholder, groups, chip,
|
|
|
1418
1445
|
}
|
|
1419
1446
|
)
|
|
1420
1447
|
] }),
|
|
1421
|
-
/* @__PURE__ */
|
|
1448
|
+
/* @__PURE__ */ jsxs16(ScrollArea, { viewportClassName: "max-h-[420px]", contentClassName: "flex flex-col p-2", children: [
|
|
1422
1449
|
children != null && /* @__PURE__ */ jsx22("div", { className: "flex flex-col gap-2 px-3 pb-2 pt-3", children }),
|
|
1423
|
-
/* @__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: [
|
|
1424
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 }) }),
|
|
1425
1452
|
/* @__PURE__ */ jsx22(Autocomplete.Collection, { children: (row) => (
|
|
1426
1453
|
/* The menu row, as the list's own option — the way Select
|
|
@@ -1438,10 +1465,11 @@ function CommandPaletteSearch({ query, onQueryChange, placeholder, groups, chip,
|
|
|
1438
1465
|
) }, row.id)
|
|
1439
1466
|
) })
|
|
1440
1467
|
] }, group.value) }),
|
|
1441
|
-
/* @__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: [
|
|
1442
1469
|
/* @__PURE__ */ jsx22(IconLoader22, { size: 12, stroke: 1.5, className: "shrink-0 animate-spin text-text-muted" }),
|
|
1443
1470
|
/* @__PURE__ */ jsx22("span", { className: "text-caption text-text-muted", children: pending })
|
|
1444
1471
|
] }) }),
|
|
1472
|
+
notes.map((note) => /* @__PURE__ */ jsx22("div", { className: "flex min-h-8 items-center px-3", children: /* @__PURE__ */ jsx22(FieldLine, { children: note }) }, note)),
|
|
1445
1473
|
/* @__PURE__ */ jsx22(Autocomplete.Empty, { className: "flex items-center px-3 [&:not(:empty)]:min-h-10", children: empty && /* @__PURE__ */ jsx22(EmptyState, { scope: "section", message: empty }) })
|
|
1446
1474
|
] }),
|
|
1447
1475
|
/* @__PURE__ */ jsx22(Footer, { keys })
|
|
@@ -1513,13 +1541,13 @@ function CommandPaletteForm({ chip, icon, submitLabel, onSubmit, submitWaits, wo
|
|
|
1513
1541
|
...backNamed ? [["Backspace", "back"]] : [],
|
|
1514
1542
|
["Esc", "close"]
|
|
1515
1543
|
];
|
|
1516
|
-
return /* @__PURE__ */
|
|
1517
|
-
/* @__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: [
|
|
1518
1546
|
icon != null && /* @__PURE__ */ jsx22("span", { className: "flex shrink-0 items-center text-text-secondary", children: icon }),
|
|
1519
1547
|
/* @__PURE__ */ jsx22(LevelChip, { chip, onBack: back })
|
|
1520
1548
|
] }),
|
|
1521
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 }) }) }),
|
|
1522
|
-
/* @__PURE__ */
|
|
1550
|
+
/* @__PURE__ */ jsxs16("div", { className: "flex shrink-0 items-center gap-3 px-5 pb-4", children: [
|
|
1523
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 }),
|
|
1524
1552
|
/* @__PURE__ */ jsx22(
|
|
1525
1553
|
Button,
|
|
@@ -1538,8 +1566,8 @@ function CommandPaletteForm({ chip, icon, submitLabel, onSubmit, submitWaits, wo
|
|
|
1538
1566
|
}
|
|
1539
1567
|
var BAR_WIDTHS = ["w-4/5", "w-3/5", "w-2/3"];
|
|
1540
1568
|
function CommandPaletteWorking({ children, bars = 2 }) {
|
|
1541
|
-
return /* @__PURE__ */
|
|
1542
|
-
/* @__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: [
|
|
1543
1571
|
/* @__PURE__ */ jsx22(IconLoader22, { size: 14, stroke: 1.5, className: "shrink-0 animate-spin" }),
|
|
1544
1572
|
children
|
|
1545
1573
|
] }),
|
|
@@ -1548,7 +1576,7 @@ function CommandPaletteWorking({ children, bars = 2 }) {
|
|
|
1548
1576
|
}
|
|
1549
1577
|
function CommandPaletteAnswer({ children, note }) {
|
|
1550
1578
|
const paragraphs = children.split(/\n\s*\n/).filter((p) => p.trim() !== "");
|
|
1551
|
-
return /* @__PURE__ */
|
|
1579
|
+
return /* @__PURE__ */ jsxs16("div", { className: "flex flex-col gap-2", children: [
|
|
1552
1580
|
paragraphs.map((paragraph, i) => /* @__PURE__ */ jsx22("p", { className: "whitespace-pre-wrap text-body-2 text-text-primary", children: paragraph.split(/\s*(\[\d+\])/).map(
|
|
1553
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
|
|
1554
1582
|
) }, i)),
|
|
@@ -1560,7 +1588,7 @@ function CommandPaletteQuote({ children }) {
|
|
|
1560
1588
|
}
|
|
1561
1589
|
|
|
1562
1590
|
// src/InlineChip.tsx
|
|
1563
|
-
import { Fragment as Fragment4, jsx as jsx23, jsxs as
|
|
1591
|
+
import { Fragment as Fragment4, jsx as jsx23, jsxs as jsxs17 } from "react/jsx-runtime";
|
|
1564
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";
|
|
1565
1593
|
var INLINE_CHIP_TONE_CLASSES = {
|
|
1566
1594
|
/** A thing or a place — anything that is not a person. */
|
|
@@ -1582,7 +1610,7 @@ function inlineChipClassName(tone, className) {
|
|
|
1582
1610
|
return cn(INLINE_CHIP_CLASSES, INLINE_CHIP_TONE_CLASSES[tone], className);
|
|
1583
1611
|
}
|
|
1584
1612
|
function InlineChip({ tone = "neutral", icon, href, className, children, ...props }) {
|
|
1585
|
-
const body = /* @__PURE__ */
|
|
1613
|
+
const body = /* @__PURE__ */ jsxs17(Fragment4, { children: [
|
|
1586
1614
|
icon && /* @__PURE__ */ jsx23("span", { className: "flex size-4 shrink-0 items-center justify-center text-text-secondary", children: icon }),
|
|
1587
1615
|
children
|
|
1588
1616
|
] });
|
|
@@ -1598,11 +1626,11 @@ import { useCallback, useRef as useRef3 } from "react";
|
|
|
1598
1626
|
|
|
1599
1627
|
// src/Divider.tsx
|
|
1600
1628
|
import { Separator } from "@base-ui/react/separator";
|
|
1601
|
-
import { jsx as jsx24, jsxs as
|
|
1629
|
+
import { jsx as jsx24, jsxs as jsxs18 } from "react/jsx-runtime";
|
|
1602
1630
|
function Divider({ orientation = "horizontal", label, tone = "default", className }) {
|
|
1603
1631
|
if (label && orientation === "horizontal") {
|
|
1604
1632
|
const line = tone === "warning" ? "bg-warning-muted" : "bg-border-subtle";
|
|
1605
|
-
return /* @__PURE__ */
|
|
1633
|
+
return /* @__PURE__ */ jsxs18(
|
|
1606
1634
|
Separator,
|
|
1607
1635
|
{
|
|
1608
1636
|
orientation: "horizontal",
|
|
@@ -1626,13 +1654,13 @@ function Divider({ orientation = "horizontal", label, tone = "default", classNam
|
|
|
1626
1654
|
}
|
|
1627
1655
|
|
|
1628
1656
|
// src/Person.tsx
|
|
1629
|
-
import { jsx as jsx25, jsxs as
|
|
1657
|
+
import { jsx as jsx25, jsxs as jsxs19 } from "react/jsx-runtime";
|
|
1630
1658
|
function Person({ name, picture, fallback = "\u2014", size = 20, className }) {
|
|
1631
1659
|
return (
|
|
1632
1660
|
// gap-2: the face-to-name distance is one rule (8px) wherever a person
|
|
1633
1661
|
// appears — Katerina, 2026-09-01, set on Person so PersonTrigger and every
|
|
1634
1662
|
// row agree by construction.
|
|
1635
|
-
/* @__PURE__ */
|
|
1663
|
+
/* @__PURE__ */ jsxs19("span", { className: cn("flex min-w-0 items-center gap-2", className), children: [
|
|
1636
1664
|
/* @__PURE__ */ jsx25(Avatar, { name, src: picture, size }),
|
|
1637
1665
|
/* @__PURE__ */ jsx25("span", { className: cn("truncate", !name && "text-text-muted"), children: name ?? fallback })
|
|
1638
1666
|
] })
|
|
@@ -1642,7 +1670,7 @@ function Person({ name, picture, fallback = "\u2014", size = 20, className }) {
|
|
|
1642
1670
|
// src/PersonTrigger.tsx
|
|
1643
1671
|
import { Button as BaseButton5 } from "@base-ui/react/button";
|
|
1644
1672
|
import { IconChevronDown } from "@tabler/icons-react";
|
|
1645
|
-
import { jsx as jsx26, jsxs as
|
|
1673
|
+
import { jsx as jsx26, jsxs as jsxs20 } from "react/jsx-runtime";
|
|
1646
1674
|
function PersonTrigger({ name, picture, fallback, size, open = false, compact = false, className, ...props }) {
|
|
1647
1675
|
if (compact) {
|
|
1648
1676
|
return /* @__PURE__ */ jsx26(
|
|
@@ -1658,7 +1686,7 @@ function PersonTrigger({ name, picture, fallback, size, open = false, compact =
|
|
|
1658
1686
|
}
|
|
1659
1687
|
);
|
|
1660
1688
|
}
|
|
1661
|
-
return /* @__PURE__ */
|
|
1689
|
+
return /* @__PURE__ */ jsxs20(
|
|
1662
1690
|
BaseButton5,
|
|
1663
1691
|
{
|
|
1664
1692
|
type: "button",
|
|
@@ -1684,7 +1712,7 @@ function PersonTrigger({ name, picture, fallback, size, open = false, compact =
|
|
|
1684
1712
|
}
|
|
1685
1713
|
|
|
1686
1714
|
// src/IdentityMenu.tsx
|
|
1687
|
-
import { Fragment as Fragment5, jsx as jsx27, jsxs as
|
|
1715
|
+
import { Fragment as Fragment5, jsx as jsx27, jsxs as jsxs21 } from "react/jsx-runtime";
|
|
1688
1716
|
function IdentityPanel({ className, onClose = () => {
|
|
1689
1717
|
}, ...rest }) {
|
|
1690
1718
|
return /* @__PURE__ */ jsx27(MenuPanel, { className: cn("w-72", className), children: /* @__PURE__ */ jsx27(IdentityRows, { ...rest, onClose }) });
|
|
@@ -1695,23 +1723,23 @@ function IdentityRows({ me, signedIn, relayUrl, idBase, onCopyKey, onSignOut, on
|
|
|
1695
1723
|
action();
|
|
1696
1724
|
};
|
|
1697
1725
|
const appRows = typeof children === "function" ? children(onClose) : children;
|
|
1698
|
-
return /* @__PURE__ */
|
|
1699
|
-
/* @__PURE__ */
|
|
1726
|
+
return /* @__PURE__ */ jsxs21(Fragment5, { children: [
|
|
1727
|
+
/* @__PURE__ */ jsxs21(MenuSection, { label: signedIn ? "Signed in as" : "Acting as", children: [
|
|
1700
1728
|
/* @__PURE__ */ jsx27(MenuRow, { children: /* @__PURE__ */ jsx27(Person, { name: me.name, picture: me.picture, fallback: "Anonymous", size: 28, className: "text-body-2-strong" }) }),
|
|
1701
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." }),
|
|
1702
|
-
me.email && /* @__PURE__ */
|
|
1730
|
+
me.email && /* @__PURE__ */ jsxs21(Note, { children: [
|
|
1703
1731
|
me.email,
|
|
1704
1732
|
" \xB7 known to Estiva, never published to the relay"
|
|
1705
1733
|
] })
|
|
1706
1734
|
] }),
|
|
1707
|
-
relayUrl && /* @__PURE__ */
|
|
1735
|
+
relayUrl && /* @__PURE__ */ jsxs21(Fragment5, { children: [
|
|
1708
1736
|
/* @__PURE__ */ jsx27(Divider, { className: "mx-0 my-2" }),
|
|
1709
|
-
/* @__PURE__ */
|
|
1737
|
+
/* @__PURE__ */ jsxs21(MenuSection, { label: "Workspace", children: [
|
|
1710
1738
|
/* @__PURE__ */ jsx27(MenuRow, { children: /* @__PURE__ */ jsx27("span", { className: "break-all font-mono text-caption text-text-primary", children: relayUrl }) }),
|
|
1711
1739
|
/* @__PURE__ */ jsx27(Note, { children: "Everyone on this relay shares this workspace, in every app." })
|
|
1712
1740
|
] })
|
|
1713
1741
|
] }),
|
|
1714
|
-
appRows && /* @__PURE__ */
|
|
1742
|
+
appRows && /* @__PURE__ */ jsxs21(Fragment5, { children: [
|
|
1715
1743
|
/* @__PURE__ */ jsx27(Divider, { className: "mx-0 my-2" }),
|
|
1716
1744
|
appRows
|
|
1717
1745
|
] }),
|
|
@@ -1773,15 +1801,99 @@ function Note({ children }) {
|
|
|
1773
1801
|
return /* @__PURE__ */ jsx27("span", { className: "px-2 pb-1.5 text-caption text-text-secondary", children });
|
|
1774
1802
|
}
|
|
1775
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
|
+
|
|
1776
1888
|
// src/Select.tsx
|
|
1777
1889
|
import { IconCheck as IconCheck2, IconChevronDown as IconChevronDown2 } from "@tabler/icons-react";
|
|
1778
1890
|
import { Select as BaseSelect } from "@base-ui/react/select";
|
|
1779
|
-
import { jsx as
|
|
1891
|
+
import { jsx as jsx30, jsxs as jsxs22 } from "react/jsx-runtime";
|
|
1780
1892
|
var GAP4 = 4;
|
|
1781
1893
|
var VIEWPORT_PAD4 = 8;
|
|
1782
1894
|
function Select({ value, onChange, options, size = "default", ariaLabel, placeholder = "Select\u2026", disabled, className, ...aria }) {
|
|
1783
1895
|
const selected = options.find((o) => o.value === value);
|
|
1784
|
-
return /* @__PURE__ */
|
|
1896
|
+
return /* @__PURE__ */ jsxs22(
|
|
1785
1897
|
BaseSelect.Root,
|
|
1786
1898
|
{
|
|
1787
1899
|
value,
|
|
@@ -1789,7 +1901,7 @@ function Select({ value, onChange, options, size = "default", ariaLabel, placeho
|
|
|
1789
1901
|
disabled,
|
|
1790
1902
|
modal: false,
|
|
1791
1903
|
children: [
|
|
1792
|
-
/* @__PURE__ */
|
|
1904
|
+
/* @__PURE__ */ jsxs22(
|
|
1793
1905
|
BaseSelect.Trigger,
|
|
1794
1906
|
{
|
|
1795
1907
|
"aria-label": ariaLabel,
|
|
@@ -1816,20 +1928,20 @@ function Select({ value, onChange, options, size = "default", ariaLabel, placeho
|
|
|
1816
1928
|
className
|
|
1817
1929
|
),
|
|
1818
1930
|
children: [
|
|
1819
|
-
/* @__PURE__ */
|
|
1820
|
-
selected?.leading && /* @__PURE__ */
|
|
1821
|
-
/* @__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 })
|
|
1822
1934
|
] }),
|
|
1823
|
-
/* @__PURE__ */
|
|
1935
|
+
/* @__PURE__ */ jsx30(
|
|
1824
1936
|
BaseSelect.Icon,
|
|
1825
1937
|
{
|
|
1826
|
-
render: /* @__PURE__ */
|
|
1938
|
+
render: /* @__PURE__ */ jsx30(IconChevronDown2, { size: size === "small" ? 14 : 16, stroke: 1.5, className: "shrink-0 text-text-secondary" })
|
|
1827
1939
|
}
|
|
1828
1940
|
)
|
|
1829
1941
|
]
|
|
1830
1942
|
}
|
|
1831
1943
|
),
|
|
1832
|
-
/* @__PURE__ */
|
|
1944
|
+
/* @__PURE__ */ jsx30(BaseSelect.Portal, { children: /* @__PURE__ */ jsx30(
|
|
1833
1945
|
BaseSelect.Positioner,
|
|
1834
1946
|
{
|
|
1835
1947
|
side: "bottom",
|
|
@@ -1838,25 +1950,25 @@ function Select({ value, onChange, options, size = "default", ariaLabel, placeho
|
|
|
1838
1950
|
collisionPadding: VIEWPORT_PAD4,
|
|
1839
1951
|
alignItemWithTrigger: false,
|
|
1840
1952
|
className: "z-50 data-[anchor-hidden]:hidden",
|
|
1841
|
-
children: /* @__PURE__ */
|
|
1953
|
+
children: /* @__PURE__ */ jsx30(
|
|
1842
1954
|
BaseSelect.Popup,
|
|
1843
1955
|
{
|
|
1844
|
-
render: /* @__PURE__ */
|
|
1956
|
+
render: /* @__PURE__ */ jsx30(MenuPanel, {}),
|
|
1845
1957
|
className: "min-w-[var(--anchor-width)] p-0",
|
|
1846
|
-
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(
|
|
1847
1959
|
BaseSelect.Item,
|
|
1848
1960
|
{
|
|
1849
1961
|
value: option.value,
|
|
1850
1962
|
className: cn(menuItemClassName({ size: "default" }), "justify-between data-[selected]:font-medium"),
|
|
1851
1963
|
children: [
|
|
1852
|
-
/* @__PURE__ */
|
|
1853
|
-
option.leading && /* @__PURE__ */
|
|
1854
|
-
/* @__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 })
|
|
1855
1967
|
] }),
|
|
1856
|
-
/* @__PURE__ */
|
|
1968
|
+
/* @__PURE__ */ jsx30(
|
|
1857
1969
|
BaseSelect.ItemIndicator,
|
|
1858
1970
|
{
|
|
1859
|
-
render: /* @__PURE__ */
|
|
1971
|
+
render: /* @__PURE__ */ jsx30(IconCheck2, { size: 16, stroke: 1.5, className: "shrink-0 text-text-secondary" })
|
|
1860
1972
|
}
|
|
1861
1973
|
)
|
|
1862
1974
|
]
|
|
@@ -1873,17 +1985,20 @@ function Select({ value, onChange, options, size = "default", ariaLabel, placeho
|
|
|
1873
1985
|
}
|
|
1874
1986
|
|
|
1875
1987
|
// src/TextInput.tsx
|
|
1876
|
-
import { forwardRef } from "react";
|
|
1988
|
+
import { forwardRef as forwardRef2 } from "react";
|
|
1877
1989
|
import { Input } from "@base-ui/react/input";
|
|
1878
|
-
import { jsx as
|
|
1879
|
-
var TextInput =
|
|
1880
|
-
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(
|
|
1881
1993
|
Input,
|
|
1882
1994
|
{
|
|
1883
1995
|
ref,
|
|
1884
1996
|
type,
|
|
1885
1997
|
className: cn(
|
|
1886
|
-
|
|
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",
|
|
1887
2002
|
// The small size is the small Select's trigger, class for class.
|
|
1888
2003
|
size === "default" && "px-3 py-2 text-input-value",
|
|
1889
2004
|
size === "small" && "h-6 px-2 text-caption",
|
|
@@ -1899,17 +2014,20 @@ var TextInput = forwardRef(function TextInput2({ className, type = "text", size
|
|
|
1899
2014
|
});
|
|
1900
2015
|
|
|
1901
2016
|
// src/Textarea.tsx
|
|
1902
|
-
import { forwardRef as
|
|
1903
|
-
import { Field as
|
|
1904
|
-
import { jsx as
|
|
1905
|
-
var Textarea =
|
|
1906
|
-
return /* @__PURE__ */
|
|
1907
|
-
|
|
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,
|
|
1908
2023
|
{
|
|
1909
2024
|
ref,
|
|
1910
|
-
render: /* @__PURE__ */
|
|
2025
|
+
render: /* @__PURE__ */ jsx32("textarea", {}),
|
|
1911
2026
|
className: cn(
|
|
1912
|
-
|
|
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",
|
|
1913
2031
|
"text-input-value text-text-primary placeholder:text-text-muted",
|
|
1914
2032
|
"resize-none outline-none transition-colors",
|
|
1915
2033
|
"disabled:pointer-events-none disabled:bg-bg-disabled disabled:text-text-disabled",
|
|
@@ -1925,24 +2043,24 @@ var Textarea = forwardRef2(function Textarea2({ className, ...props }, ref) {
|
|
|
1925
2043
|
import { useState as useState4 } from "react";
|
|
1926
2044
|
|
|
1927
2045
|
// src/DialogShell.tsx
|
|
1928
|
-
import { useRef as
|
|
2046
|
+
import { useRef as useRef5 } from "react";
|
|
1929
2047
|
import { Dialog as Dialog2 } from "@base-ui/react/dialog";
|
|
1930
2048
|
import { AlertDialog } from "@base-ui/react/alert-dialog";
|
|
1931
2049
|
import { IconX as IconX4 } from "@tabler/icons-react";
|
|
1932
|
-
import { jsx as
|
|
2050
|
+
import { jsx as jsx33, jsxs as jsxs23 } from "react/jsx-runtime";
|
|
1933
2051
|
function DialogShell({ title, onClose, headerContent, footer, children, bodyClassName, bodyMaxHeight, width = 502, alert = false }) {
|
|
1934
2052
|
const Parts = alert ? AlertDialog : Dialog2;
|
|
1935
|
-
const popupRef =
|
|
1936
|
-
return /* @__PURE__ */
|
|
2053
|
+
const popupRef = useRef5(null);
|
|
2054
|
+
return /* @__PURE__ */ jsx33(
|
|
1937
2055
|
Parts.Root,
|
|
1938
2056
|
{
|
|
1939
2057
|
open: true,
|
|
1940
2058
|
onOpenChange: (open) => {
|
|
1941
2059
|
if (!open) onClose();
|
|
1942
2060
|
},
|
|
1943
|
-
children: /* @__PURE__ */
|
|
1944
|
-
/* @__PURE__ */
|
|
1945
|
-
/* @__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(
|
|
1946
2064
|
Parts.Popup,
|
|
1947
2065
|
{
|
|
1948
2066
|
ref: popupRef,
|
|
@@ -1951,16 +2069,16 @@ function DialogShell({ title, onClose, headerContent, footer, children, bodyClas
|
|
|
1951
2069
|
className: "bg-bg-elevated border border-border-subtle rounded-lg shadow-lg pointer-events-auto flex flex-col overflow-hidden outline-none",
|
|
1952
2070
|
style: { width },
|
|
1953
2071
|
children: [
|
|
1954
|
-
/* @__PURE__ */
|
|
1955
|
-
headerContent ?? /* @__PURE__ */
|
|
1956
|
-
/* @__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(
|
|
1957
2075
|
Parts.Close,
|
|
1958
2076
|
{
|
|
1959
|
-
render: /* @__PURE__ */
|
|
2077
|
+
render: /* @__PURE__ */ jsx33(IconButton, { tooltip: "Close", "aria-label": "Close", children: /* @__PURE__ */ jsx33(IconX4, { size: 16, stroke: 1.5 }) })
|
|
1960
2078
|
}
|
|
1961
2079
|
)
|
|
1962
2080
|
] }),
|
|
1963
|
-
bodyMaxHeight ? /* @__PURE__ */
|
|
2081
|
+
bodyMaxHeight ? /* @__PURE__ */ jsx33(
|
|
1964
2082
|
ScrollArea,
|
|
1965
2083
|
{
|
|
1966
2084
|
className: cn(footer != null && "border-b border-border-subtle"),
|
|
@@ -1968,8 +2086,8 @@ function DialogShell({ title, onClose, headerContent, footer, children, bodyClas
|
|
|
1968
2086
|
contentClassName: cn("pl-5 pr-4 py-4", bodyClassName),
|
|
1969
2087
|
children
|
|
1970
2088
|
}
|
|
1971
|
-
) : /* @__PURE__ */
|
|
1972
|
-
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 })
|
|
1973
2091
|
]
|
|
1974
2092
|
}
|
|
1975
2093
|
) })
|
|
@@ -1979,7 +2097,7 @@ function DialogShell({ title, onClose, headerContent, footer, children, bodyClas
|
|
|
1979
2097
|
}
|
|
1980
2098
|
|
|
1981
2099
|
// src/ConfirmDialog.tsx
|
|
1982
|
-
import { Fragment as Fragment6, jsx as
|
|
2100
|
+
import { Fragment as Fragment6, jsx as jsx34, jsxs as jsxs24 } from "react/jsx-runtime";
|
|
1983
2101
|
function ConfirmDialog({ title, children, confirmLabel, destructive = false, onConfirm, onClose }) {
|
|
1984
2102
|
const [busy, setBusy] = useState4(false);
|
|
1985
2103
|
const confirm = async () => {
|
|
@@ -1991,16 +2109,16 @@ function ConfirmDialog({ title, children, confirmLabel, destructive = false, onC
|
|
|
1991
2109
|
setBusy(false);
|
|
1992
2110
|
}
|
|
1993
2111
|
};
|
|
1994
|
-
return /* @__PURE__ */
|
|
2112
|
+
return /* @__PURE__ */ jsx34(
|
|
1995
2113
|
DialogShell,
|
|
1996
2114
|
{
|
|
1997
2115
|
alert: true,
|
|
1998
2116
|
title,
|
|
1999
2117
|
onClose,
|
|
2000
2118
|
bodyClassName: "flex flex-col gap-3 text-body-2 text-text-primary",
|
|
2001
|
-
footer: /* @__PURE__ */
|
|
2002
|
-
/* @__PURE__ */
|
|
2003
|
-
/* @__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 })
|
|
2004
2122
|
] }),
|
|
2005
2123
|
children
|
|
2006
2124
|
}
|
|
@@ -2008,15 +2126,15 @@ function ConfirmDialog({ title, children, confirmLabel, destructive = false, onC
|
|
|
2008
2126
|
}
|
|
2009
2127
|
|
|
2010
2128
|
// src/EditableText.tsx
|
|
2011
|
-
import { useEffect as useEffect2, useRef as
|
|
2012
|
-
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";
|
|
2013
2131
|
import { Input as Input2 } from "@base-ui/react/input";
|
|
2014
|
-
import { jsx as
|
|
2132
|
+
import { jsx as jsx35 } from "react/jsx-runtime";
|
|
2015
2133
|
function EditableText({ value, display, displayNode, placeholder, onCommit, multiline = false, className, label, readOnly = false }) {
|
|
2016
2134
|
const [editing, setEditing] = useState5(false);
|
|
2017
2135
|
const [draft, setDraft] = useState5(value);
|
|
2018
2136
|
const [busy, setBusy] = useState5(false);
|
|
2019
|
-
const fieldRef =
|
|
2137
|
+
const fieldRef = useRef6(null);
|
|
2020
2138
|
useEffect2(() => {
|
|
2021
2139
|
if (editing) {
|
|
2022
2140
|
fieldRef.current?.focus();
|
|
@@ -2069,7 +2187,7 @@ function EditableText({ value, display, displayNode, placeholder, onCommit, mult
|
|
|
2069
2187
|
written and never read. Read-only, this is a line of text: whatever
|
|
2070
2188
|
names the region around it (a `Field`, a `Property`) names this too.
|
|
2071
2189
|
*/
|
|
2072
|
-
/* @__PURE__ */
|
|
2190
|
+
/* @__PURE__ */ jsx35(
|
|
2073
2191
|
"div",
|
|
2074
2192
|
{
|
|
2075
2193
|
className: cn("w-full px-2 py-1", multiline && !displayNode && "whitespace-pre-wrap", display ?? value ? "text-text-primary" : "text-text-muted", className),
|
|
@@ -2079,11 +2197,11 @@ function EditableText({ value, display, displayNode, placeholder, onCommit, mult
|
|
|
2079
2197
|
);
|
|
2080
2198
|
}
|
|
2081
2199
|
if (editing) {
|
|
2082
|
-
return multiline ? /* @__PURE__ */
|
|
2083
|
-
|
|
2200
|
+
return multiline ? /* @__PURE__ */ jsx35(
|
|
2201
|
+
BaseField4.Control,
|
|
2084
2202
|
{
|
|
2085
2203
|
ref: fieldRef,
|
|
2086
|
-
render: /* @__PURE__ */
|
|
2204
|
+
render: /* @__PURE__ */ jsx35("textarea", { rows: 4 }),
|
|
2087
2205
|
"aria-label": label,
|
|
2088
2206
|
value: draft,
|
|
2089
2207
|
disabled: busy,
|
|
@@ -2092,7 +2210,7 @@ function EditableText({ value, display, displayNode, placeholder, onCommit, mult
|
|
|
2092
2210
|
onBlur: () => void commit(),
|
|
2093
2211
|
className: fieldClass
|
|
2094
2212
|
}
|
|
2095
|
-
) : /* @__PURE__ */
|
|
2213
|
+
) : /* @__PURE__ */ jsx35(
|
|
2096
2214
|
Input2,
|
|
2097
2215
|
{
|
|
2098
2216
|
ref: fieldRef,
|
|
@@ -2106,7 +2224,7 @@ function EditableText({ value, display, displayNode, placeholder, onCommit, mult
|
|
|
2106
2224
|
}
|
|
2107
2225
|
);
|
|
2108
2226
|
}
|
|
2109
|
-
return /* @__PURE__ */
|
|
2227
|
+
return /* @__PURE__ */ jsx35(
|
|
2110
2228
|
"button",
|
|
2111
2229
|
{
|
|
2112
2230
|
type: "button",
|
|
@@ -2125,7 +2243,7 @@ function EditableText({ value, display, displayNode, placeholder, onCommit, mult
|
|
|
2125
2243
|
|
|
2126
2244
|
// src/ProgressBar.tsx
|
|
2127
2245
|
import { Progress } from "@base-ui/react/progress";
|
|
2128
|
-
import { jsx as
|
|
2246
|
+
import { jsx as jsx36 } from "react/jsx-runtime";
|
|
2129
2247
|
var TRACK_CLASSES = {
|
|
2130
2248
|
default: "h-1.5 w-full overflow-hidden rounded-full bg-bg-inset",
|
|
2131
2249
|
// 4px, Katerina's ruling of 14 September; Peek's own bar is 3px until it takes this one.
|
|
@@ -2138,16 +2256,16 @@ var INDICATOR_CLASSES = {
|
|
|
2138
2256
|
function ProgressBar({ value, max, label, variant = "default", className }) {
|
|
2139
2257
|
return (
|
|
2140
2258
|
// `max={0}` needs no guard: Base UI reads the 0/0 share as an empty bar.
|
|
2141
|
-
/* @__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] }) }) })
|
|
2142
2260
|
);
|
|
2143
2261
|
}
|
|
2144
2262
|
|
|
2145
2263
|
// src/Breadcrumb.tsx
|
|
2146
|
-
import { Fragment as Fragment7, useCallback as useCallback2, useLayoutEffect as
|
|
2147
|
-
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";
|
|
2148
2266
|
function Breadcrumb({ items, className }) {
|
|
2149
|
-
const navRef =
|
|
2150
|
-
const labelRefs =
|
|
2267
|
+
const navRef = useRef7(null);
|
|
2268
|
+
const labelRefs = useRef7([]);
|
|
2151
2269
|
const [truncated, setTruncated] = useState6(/* @__PURE__ */ new Set());
|
|
2152
2270
|
const measure = useCallback2(() => {
|
|
2153
2271
|
const next = /* @__PURE__ */ new Set();
|
|
@@ -2156,7 +2274,7 @@ function Breadcrumb({ items, className }) {
|
|
|
2156
2274
|
});
|
|
2157
2275
|
setTruncated((prev) => prev.size === next.size && [...next].every((i) => prev.has(i)) ? prev : next);
|
|
2158
2276
|
}, []);
|
|
2159
|
-
|
|
2277
|
+
useLayoutEffect4(() => {
|
|
2160
2278
|
measure();
|
|
2161
2279
|
const nav = navRef.current;
|
|
2162
2280
|
if (!nav || typeof ResizeObserver === "undefined") return;
|
|
@@ -2164,7 +2282,7 @@ function Breadcrumb({ items, className }) {
|
|
|
2164
2282
|
observer.observe(nav);
|
|
2165
2283
|
return () => observer.disconnect();
|
|
2166
2284
|
}, [measure, items]);
|
|
2167
|
-
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) => {
|
|
2168
2286
|
const last = index === items.length - 1;
|
|
2169
2287
|
const tone = item.muted || last && item.mono ? "text-text-muted" : last ? "text-text-primary" : "text-text-secondary";
|
|
2170
2288
|
const text = cn(
|
|
@@ -2182,25 +2300,25 @@ function Breadcrumb({ items, className }) {
|
|
|
2182
2300
|
// `plain` adds no look of its own: a crumb keeps the trail's size and
|
|
2183
2301
|
// tone, and brightens on hover. The package's own Link, so a trail
|
|
2184
2302
|
// follows whatever a link learns to do (UIG-5).
|
|
2185
|
-
/* @__PURE__ */
|
|
2186
|
-
) : /* @__PURE__ */
|
|
2187
|
-
return /* @__PURE__ */
|
|
2188
|
-
index > 0 && /* @__PURE__ */
|
|
2189
|
-
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 }),
|
|
2190
2308
|
truncated.has(index) ? (
|
|
2191
2309
|
// `min-w-0 shrink` undoes the wrapper's own shrink-0 — the crumb
|
|
2192
2310
|
// must keep truncating inside it, or wrapping it would widen the
|
|
2193
2311
|
// trail and the tooltip would never be needed again.
|
|
2194
|
-
/* @__PURE__ */
|
|
2312
|
+
/* @__PURE__ */ jsx37(WithTooltip, { label: item.label, wrapperClassName: "min-w-0 shrink", children: crumb })
|
|
2195
2313
|
) : crumb
|
|
2196
2314
|
] }, `${item.label}-${index}`);
|
|
2197
2315
|
}) });
|
|
2198
2316
|
}
|
|
2199
2317
|
|
|
2200
2318
|
// src/NavItem.tsx
|
|
2201
|
-
import { jsx as
|
|
2319
|
+
import { jsx as jsx38, jsxs as jsxs26 } from "react/jsx-runtime";
|
|
2202
2320
|
function NavItem({ label, href, count, countLabel, active = false, icon, className, ...props }) {
|
|
2203
|
-
return /* @__PURE__ */
|
|
2321
|
+
return /* @__PURE__ */ jsxs26(
|
|
2204
2322
|
"a",
|
|
2205
2323
|
{
|
|
2206
2324
|
href,
|
|
@@ -2215,9 +2333,9 @@ function NavItem({ label, href, count, countLabel, active = false, icon, classNa
|
|
|
2215
2333
|
),
|
|
2216
2334
|
...props,
|
|
2217
2335
|
children: [
|
|
2218
|
-
icon && /* @__PURE__ */
|
|
2219
|
-
/* @__PURE__ */
|
|
2220
|
-
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
|
|
2221
2339
|
]
|
|
2222
2340
|
}
|
|
2223
2341
|
);
|
|
@@ -2226,7 +2344,7 @@ function NavItem({ label, href, count, countLabel, active = false, icon, classNa
|
|
|
2226
2344
|
// src/Popover.tsx
|
|
2227
2345
|
import { useMemo as useMemo3 } from "react";
|
|
2228
2346
|
import { Popover as BasePopover } from "@base-ui/react/popover";
|
|
2229
|
-
import { jsx as
|
|
2347
|
+
import { jsx as jsx39, jsxs as jsxs27 } from "react/jsx-runtime";
|
|
2230
2348
|
var GAP5 = 4;
|
|
2231
2349
|
var VIEWPORT_PAD5 = 8;
|
|
2232
2350
|
function Popover({ trigger, anchor, align = "left", side = "bottom", open, onOpenChange, finalFocus, actionsRef, ariaLabel, children, className, contentClassName, maxHeight }) {
|
|
@@ -2235,7 +2353,7 @@ function Popover({ trigger, anchor, align = "left", side = "bottom", open, onOpe
|
|
|
2235
2353
|
if (anchor instanceof Element) return anchor;
|
|
2236
2354
|
return { getBoundingClientRect: () => anchor };
|
|
2237
2355
|
}, [anchor]);
|
|
2238
|
-
return /* @__PURE__ */
|
|
2356
|
+
return /* @__PURE__ */ jsxs27(
|
|
2239
2357
|
BasePopover.Root,
|
|
2240
2358
|
{
|
|
2241
2359
|
open,
|
|
@@ -2243,8 +2361,8 @@ function Popover({ trigger, anchor, align = "left", side = "bottom", open, onOpe
|
|
|
2243
2361
|
actionsRef,
|
|
2244
2362
|
modal: false,
|
|
2245
2363
|
children: [
|
|
2246
|
-
trigger && /* @__PURE__ */
|
|
2247
|
-
/* @__PURE__ */
|
|
2364
|
+
trigger && /* @__PURE__ */ jsx39(BasePopover.Trigger, { render: trigger, disabled: triggerDisabled(trigger) }),
|
|
2365
|
+
/* @__PURE__ */ jsx39(BasePopover.Portal, { children: /* @__PURE__ */ jsx39(
|
|
2248
2366
|
BasePopover.Positioner,
|
|
2249
2367
|
{
|
|
2250
2368
|
anchor: anchorTarget,
|
|
@@ -2253,15 +2371,15 @@ function Popover({ trigger, anchor, align = "left", side = "bottom", open, onOpe
|
|
|
2253
2371
|
sideOffset: GAP5,
|
|
2254
2372
|
collisionPadding: VIEWPORT_PAD5,
|
|
2255
2373
|
className: "z-50 data-[anchor-hidden]:hidden",
|
|
2256
|
-
children: /* @__PURE__ */
|
|
2374
|
+
children: /* @__PURE__ */ jsx39(
|
|
2257
2375
|
BasePopover.Popup,
|
|
2258
2376
|
{
|
|
2259
2377
|
"aria-label": ariaLabel,
|
|
2260
2378
|
initialFocus: trigger ? void 0 : false,
|
|
2261
2379
|
finalFocus,
|
|
2262
2380
|
className: cn("min-w-[180px] outline-none p-0", className),
|
|
2263
|
-
render: /* @__PURE__ */
|
|
2264
|
-
children: /* @__PURE__ */
|
|
2381
|
+
render: /* @__PURE__ */ jsx39(MenuPanel, {}),
|
|
2382
|
+
children: /* @__PURE__ */ jsx39(
|
|
2265
2383
|
ScrollArea,
|
|
2266
2384
|
{
|
|
2267
2385
|
viewportClassName: maxHeight ?? "max-h-[var(--available-height)]",
|
|
@@ -2280,9 +2398,9 @@ function Popover({ trigger, anchor, align = "left", side = "bottom", open, onOpe
|
|
|
2280
2398
|
|
|
2281
2399
|
// src/Toolbar.tsx
|
|
2282
2400
|
import { Toolbar as BaseToolbar } from "@base-ui/react/toolbar";
|
|
2283
|
-
import { jsx as
|
|
2401
|
+
import { jsx as jsx40 } from "react/jsx-runtime";
|
|
2284
2402
|
function Toolbar({ "aria-label": ariaLabel, orientation = "horizontal", loopFocus = true, surface = true, children, className }) {
|
|
2285
|
-
const strip = /* @__PURE__ */
|
|
2403
|
+
const strip = /* @__PURE__ */ jsx40(
|
|
2286
2404
|
BaseToolbar.Root,
|
|
2287
2405
|
{
|
|
2288
2406
|
"aria-label": ariaLabel,
|
|
@@ -2293,24 +2411,24 @@ function Toolbar({ "aria-label": ariaLabel, orientation = "horizontal", loopFocu
|
|
|
2293
2411
|
}
|
|
2294
2412
|
);
|
|
2295
2413
|
if (!surface) return strip;
|
|
2296
|
-
return /* @__PURE__ */
|
|
2414
|
+
return /* @__PURE__ */ jsx40(MenuPanel, { className: "w-fit p-1", children: strip });
|
|
2297
2415
|
}
|
|
2298
2416
|
function ToolbarButton({ ref, disabled, disabledReason, ...props }) {
|
|
2299
|
-
return /* @__PURE__ */
|
|
2417
|
+
return /* @__PURE__ */ jsx40(
|
|
2300
2418
|
BaseToolbar.Button,
|
|
2301
2419
|
{
|
|
2302
2420
|
ref,
|
|
2303
2421
|
disabled: disabled || !!disabledReason,
|
|
2304
2422
|
focusableWhenDisabled: true,
|
|
2305
|
-
render: /* @__PURE__ */
|
|
2423
|
+
render: /* @__PURE__ */ jsx40(IconButton, { disabled, disabledReason, ...props })
|
|
2306
2424
|
}
|
|
2307
2425
|
);
|
|
2308
2426
|
}
|
|
2309
2427
|
function ToolbarInput({ size, ...props }) {
|
|
2310
|
-
return /* @__PURE__ */
|
|
2428
|
+
return /* @__PURE__ */ jsx40(BaseToolbar.Input, { render: /* @__PURE__ */ jsx40(TextInput, { size }), ...props });
|
|
2311
2429
|
}
|
|
2312
2430
|
function ToolbarSeparator({ className }) {
|
|
2313
|
-
return /* @__PURE__ */
|
|
2431
|
+
return /* @__PURE__ */ jsx40(
|
|
2314
2432
|
BaseToolbar.Separator,
|
|
2315
2433
|
{
|
|
2316
2434
|
orientation: "vertical",
|
|
@@ -2320,9 +2438,9 @@ function ToolbarSeparator({ className }) {
|
|
|
2320
2438
|
}
|
|
2321
2439
|
|
|
2322
2440
|
// src/ReactionPicker.tsx
|
|
2323
|
-
import { jsx as
|
|
2441
|
+
import { jsx as jsx41 } from "react/jsx-runtime";
|
|
2324
2442
|
function ReactionPicker({ options, onSelect, "aria-label": ariaLabel = "Reactions", surface = true, className }) {
|
|
2325
|
-
return /* @__PURE__ */
|
|
2443
|
+
return /* @__PURE__ */ jsx41(Toolbar, { "aria-label": ariaLabel, surface, className: cn("gap-0.5", className), children: options.map((option) => (
|
|
2326
2444
|
/*
|
|
2327
2445
|
A `ToolbarButton`, not a button in a tooltip wrapper. The wrapper
|
|
2328
2446
|
would become the toolbar's item and the button inside it would never
|
|
@@ -2332,14 +2450,14 @@ function ReactionPicker({ options, onSelect, "aria-label": ariaLabel = "Reaction
|
|
|
2332
2450
|
The tooltip names it for a pointer, `aria-label` for everything else,
|
|
2333
2451
|
and both say the meaning rather than the glyph.
|
|
2334
2452
|
*/
|
|
2335
|
-
/* @__PURE__ */
|
|
2453
|
+
/* @__PURE__ */ jsx41(
|
|
2336
2454
|
ToolbarButton,
|
|
2337
2455
|
{
|
|
2338
2456
|
"aria-label": option.label,
|
|
2339
2457
|
tooltip: option.label,
|
|
2340
2458
|
onClick: () => onSelect(option.emoji),
|
|
2341
2459
|
className: "size-7 text-h3 leading-none",
|
|
2342
|
-
children: /* @__PURE__ */
|
|
2460
|
+
children: /* @__PURE__ */ jsx41("span", { "aria-hidden": "true", children: option.emoji })
|
|
2343
2461
|
},
|
|
2344
2462
|
option.emoji
|
|
2345
2463
|
)
|
|
@@ -2348,23 +2466,23 @@ function ReactionPicker({ options, onSelect, "aria-label": ariaLabel = "Reaction
|
|
|
2348
2466
|
|
|
2349
2467
|
// src/PreviewCard.tsx
|
|
2350
2468
|
import { PreviewCard as BasePreviewCard } from "@base-ui/react/preview-card";
|
|
2351
|
-
import { jsx as
|
|
2469
|
+
import { jsx as jsx42, jsxs as jsxs28 } from "react/jsx-runtime";
|
|
2352
2470
|
var GAP6 = 12;
|
|
2353
2471
|
var VIEWPORT_PAD6 = 8;
|
|
2354
2472
|
var OPEN_DELAY2 = 350;
|
|
2355
2473
|
var CLOSE_DELAY = 200;
|
|
2356
2474
|
function PreviewCard({ content, children, side = "right", delay = OPEN_DELAY2, closeDelay = CLOSE_DELAY, className, wrapperClassName }) {
|
|
2357
|
-
return /* @__PURE__ */
|
|
2358
|
-
/* @__PURE__ */
|
|
2475
|
+
return /* @__PURE__ */ jsxs28(BasePreviewCard.Root, { children: [
|
|
2476
|
+
/* @__PURE__ */ jsx42(
|
|
2359
2477
|
BasePreviewCard.Trigger,
|
|
2360
2478
|
{
|
|
2361
2479
|
delay,
|
|
2362
2480
|
closeDelay,
|
|
2363
|
-
render: /* @__PURE__ */
|
|
2481
|
+
render: /* @__PURE__ */ jsx42("span", { className: cn("inline-flex", wrapperClassName) }),
|
|
2364
2482
|
children
|
|
2365
2483
|
}
|
|
2366
2484
|
),
|
|
2367
|
-
/* @__PURE__ */
|
|
2485
|
+
/* @__PURE__ */ jsx42(BasePreviewCard.Portal, { children: /* @__PURE__ */ jsx42(
|
|
2368
2486
|
BasePreviewCard.Positioner,
|
|
2369
2487
|
{
|
|
2370
2488
|
side,
|
|
@@ -2372,12 +2490,12 @@ function PreviewCard({ content, children, side = "right", delay = OPEN_DELAY2, c
|
|
|
2372
2490
|
sideOffset: GAP6,
|
|
2373
2491
|
collisionPadding: VIEWPORT_PAD6,
|
|
2374
2492
|
className: "z-50 data-[anchor-hidden]:hidden",
|
|
2375
|
-
children: /* @__PURE__ */
|
|
2493
|
+
children: /* @__PURE__ */ jsx42(
|
|
2376
2494
|
BasePreviewCard.Popup,
|
|
2377
2495
|
{
|
|
2378
2496
|
className: cn("w-[360px] p-3 outline-none", className),
|
|
2379
|
-
render: /* @__PURE__ */
|
|
2380
|
-
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 })
|
|
2381
2499
|
}
|
|
2382
2500
|
)
|
|
2383
2501
|
}
|
|
@@ -2386,15 +2504,15 @@ function PreviewCard({ content, children, side = "right", delay = OPEN_DELAY2, c
|
|
|
2386
2504
|
}
|
|
2387
2505
|
|
|
2388
2506
|
// src/Rail.tsx
|
|
2389
|
-
import { jsx as
|
|
2507
|
+
import { jsx as jsx43 } from "react/jsx-runtime";
|
|
2390
2508
|
function Rail({ "aria-label": ariaLabel = "Navigation", children, className }) {
|
|
2391
|
-
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 });
|
|
2392
2510
|
}
|
|
2393
2511
|
|
|
2394
2512
|
// src/RailItem.tsx
|
|
2395
|
-
import { jsx as
|
|
2513
|
+
import { jsx as jsx44, jsxs as jsxs29 } from "react/jsx-runtime";
|
|
2396
2514
|
function RailItem({ href, icon, label, active = false, className, ...props }) {
|
|
2397
|
-
return /* @__PURE__ */
|
|
2515
|
+
return /* @__PURE__ */ jsxs29(
|
|
2398
2516
|
"a",
|
|
2399
2517
|
{
|
|
2400
2518
|
href,
|
|
@@ -2402,14 +2520,14 @@ function RailItem({ href, icon, label, active = false, className, ...props }) {
|
|
|
2402
2520
|
className: cn("group flex w-full shrink-0 flex-col items-center gap-0.5 px-2 py-0.5", className),
|
|
2403
2521
|
...props,
|
|
2404
2522
|
children: [
|
|
2405
|
-
/* @__PURE__ */
|
|
2523
|
+
/* @__PURE__ */ jsx44(
|
|
2406
2524
|
"div",
|
|
2407
2525
|
{
|
|
2408
2526
|
className: cn(
|
|
2409
2527
|
"flex items-center justify-center rounded-lg p-2 transition-colors",
|
|
2410
2528
|
active ? "bg-bg-selected" : "group-hover:bg-bg-hover"
|
|
2411
2529
|
),
|
|
2412
|
-
children: /* @__PURE__ */
|
|
2530
|
+
children: /* @__PURE__ */ jsx44(
|
|
2413
2531
|
"span",
|
|
2414
2532
|
{
|
|
2415
2533
|
className: cn(
|
|
@@ -2421,27 +2539,27 @@ function RailItem({ href, icon, label, active = false, className, ...props }) {
|
|
|
2421
2539
|
)
|
|
2422
2540
|
}
|
|
2423
2541
|
),
|
|
2424
|
-
/* @__PURE__ */
|
|
2542
|
+
/* @__PURE__ */ jsx44("span", { className: cn("text-center text-menu", active ? "text-text-primary" : "text-text-secondary"), children: label })
|
|
2425
2543
|
]
|
|
2426
2544
|
}
|
|
2427
2545
|
);
|
|
2428
2546
|
}
|
|
2429
2547
|
|
|
2430
2548
|
// src/Sidebar.tsx
|
|
2431
|
-
import { jsx as
|
|
2549
|
+
import { jsx as jsx45 } from "react/jsx-runtime";
|
|
2432
2550
|
function Sidebar({ "aria-label": ariaLabel = "Workspace", children, className }) {
|
|
2433
|
-
return /* @__PURE__ */
|
|
2551
|
+
return /* @__PURE__ */ jsx45(
|
|
2434
2552
|
"nav",
|
|
2435
2553
|
{
|
|
2436
2554
|
"aria-label": ariaLabel,
|
|
2437
2555
|
className: cn("flex w-60 shrink-0 flex-col border-r border-border-default bg-bg-surface", className),
|
|
2438
|
-
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 })
|
|
2439
2557
|
}
|
|
2440
2558
|
);
|
|
2441
2559
|
}
|
|
2442
2560
|
|
|
2443
2561
|
// src/Property.tsx
|
|
2444
|
-
import { jsx as
|
|
2562
|
+
import { jsx as jsx46, jsxs as jsxs30 } from "react/jsx-runtime";
|
|
2445
2563
|
var VALUE_CLASSES = "contents";
|
|
2446
2564
|
function Property({ label, layout = "row", children, className }) {
|
|
2447
2565
|
if (layout === "stacked") {
|
|
@@ -2449,23 +2567,23 @@ function Property({ label, layout = "row", children, className }) {
|
|
|
2449
2567
|
// gap-3 — the one label-above-content distance (Katerina, 2026-09-01):
|
|
2450
2568
|
// Peek's topic-details sections already sit at 12px, Ship's rail was
|
|
2451
2569
|
// 6px, and unifying means the bigger, calmer one.
|
|
2452
|
-
/* @__PURE__ */
|
|
2453
|
-
/* @__PURE__ */
|
|
2454
|
-
/* @__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 })
|
|
2455
2573
|
] })
|
|
2456
2574
|
);
|
|
2457
2575
|
}
|
|
2458
|
-
return /* @__PURE__ */
|
|
2459
|
-
/* @__PURE__ */
|
|
2460
|
-
/* @__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 })
|
|
2461
2579
|
] });
|
|
2462
2580
|
}
|
|
2463
2581
|
|
|
2464
2582
|
// src/Reaction.tsx
|
|
2465
2583
|
import { Toggle } from "@base-ui/react/toggle";
|
|
2466
|
-
import { jsx as
|
|
2584
|
+
import { jsx as jsx47, jsxs as jsxs31 } from "react/jsx-runtime";
|
|
2467
2585
|
function Reaction({ emoji, count, pressed = false, className, ...props }) {
|
|
2468
|
-
return /* @__PURE__ */
|
|
2586
|
+
return /* @__PURE__ */ jsxs31(
|
|
2469
2587
|
Toggle,
|
|
2470
2588
|
{
|
|
2471
2589
|
pressed,
|
|
@@ -2487,8 +2605,8 @@ function Reaction({ emoji, count, pressed = false, className, ...props }) {
|
|
|
2487
2605
|
),
|
|
2488
2606
|
...props,
|
|
2489
2607
|
children: [
|
|
2490
|
-
/* @__PURE__ */
|
|
2491
|
-
/* @__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 })
|
|
2492
2610
|
]
|
|
2493
2611
|
}
|
|
2494
2612
|
);
|
|
@@ -2497,19 +2615,21 @@ function Reaction({ emoji, count, pressed = false, className, ...props }) {
|
|
|
2497
2615
|
// src/SearchInput.tsx
|
|
2498
2616
|
import "react";
|
|
2499
2617
|
import { Input as Input3 } from "@base-ui/react/input";
|
|
2500
|
-
import { jsx as
|
|
2618
|
+
import { jsx as jsx48, jsxs as jsxs32 } from "react/jsx-runtime";
|
|
2501
2619
|
function SearchInput({ shortcut, className, placeholder = "Search\u2026", ...props }) {
|
|
2502
|
-
return /* @__PURE__ */
|
|
2620
|
+
return /* @__PURE__ */ jsxs32(
|
|
2503
2621
|
"div",
|
|
2504
2622
|
{
|
|
2505
2623
|
className: cn(
|
|
2506
2624
|
"flex gap-2 items-center px-3 py-2 rounded-lg",
|
|
2507
2625
|
"bg-bg-inset border border-border-default",
|
|
2508
|
-
|
|
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",
|
|
2509
2629
|
className
|
|
2510
2630
|
),
|
|
2511
2631
|
children: [
|
|
2512
|
-
/* @__PURE__ */
|
|
2632
|
+
/* @__PURE__ */ jsx48(
|
|
2513
2633
|
Input3,
|
|
2514
2634
|
{
|
|
2515
2635
|
className: "flex-1 min-w-0 bg-transparent text-input-value text-text-primary placeholder:text-text-muted outline-none",
|
|
@@ -2517,7 +2637,7 @@ function SearchInput({ shortcut, className, placeholder = "Search\u2026", ...pro
|
|
|
2517
2637
|
...props
|
|
2518
2638
|
}
|
|
2519
2639
|
),
|
|
2520
|
-
shortcut && /* @__PURE__ */
|
|
2640
|
+
shortcut && /* @__PURE__ */ jsx48(Kbd, { children: shortcut })
|
|
2521
2641
|
]
|
|
2522
2642
|
}
|
|
2523
2643
|
);
|
|
@@ -2526,17 +2646,17 @@ function SearchInput({ shortcut, className, placeholder = "Search\u2026", ...pro
|
|
|
2526
2646
|
// src/SectionHeader.tsx
|
|
2527
2647
|
import { IconChevronRight as IconChevronRight2 } from "@tabler/icons-react";
|
|
2528
2648
|
import { useRender } from "@base-ui/react/use-render";
|
|
2529
|
-
import { Fragment as Fragment8, jsx as
|
|
2649
|
+
import { Fragment as Fragment8, jsx as jsx49, jsxs as jsxs33 } from "react/jsx-runtime";
|
|
2530
2650
|
function SectionHeader({ title, chevron = false, isExpanded = true, onToggle, trailing, actions, showActions = "hover", render, className }) {
|
|
2531
2651
|
const titleElement = useRender({
|
|
2532
|
-
render: render ?? (chevron ? /* @__PURE__ */
|
|
2652
|
+
render: render ?? (chevron ? /* @__PURE__ */ jsx49("button", { type: "button", onClick: onToggle, "aria-expanded": isExpanded }) : /* @__PURE__ */ jsx49("span", {})),
|
|
2533
2653
|
props: {
|
|
2534
2654
|
// `text-left`: a button centres its text. `h-full` and `flex-1`: the
|
|
2535
2655
|
// whole row up to the actions is the hit target, as it was when the
|
|
2536
2656
|
// row itself carried the click.
|
|
2537
2657
|
className: "flex h-full min-w-0 flex-1 items-center gap-1 text-left",
|
|
2538
|
-
children: /* @__PURE__ */
|
|
2539
|
-
chevron && /* @__PURE__ */
|
|
2658
|
+
children: /* @__PURE__ */ jsxs33(Fragment8, { children: [
|
|
2659
|
+
chevron && /* @__PURE__ */ jsx49(
|
|
2540
2660
|
IconChevronRight2,
|
|
2541
2661
|
{
|
|
2542
2662
|
size: 12,
|
|
@@ -2544,11 +2664,11 @@ function SectionHeader({ title, chevron = false, isExpanded = true, onToggle, tr
|
|
|
2544
2664
|
className: cn("shrink-0 text-text-secondary transition-transform duration-150", isExpanded && "rotate-90")
|
|
2545
2665
|
}
|
|
2546
2666
|
),
|
|
2547
|
-
/* @__PURE__ */
|
|
2667
|
+
/* @__PURE__ */ jsx49(SectionLabel, { children: title })
|
|
2548
2668
|
] })
|
|
2549
2669
|
}
|
|
2550
2670
|
});
|
|
2551
|
-
return /* @__PURE__ */
|
|
2671
|
+
return /* @__PURE__ */ jsxs33(
|
|
2552
2672
|
"div",
|
|
2553
2673
|
{
|
|
2554
2674
|
className: cn(
|
|
@@ -2561,15 +2681,15 @@ function SectionHeader({ title, chevron = false, isExpanded = true, onToggle, tr
|
|
|
2561
2681
|
),
|
|
2562
2682
|
children: [
|
|
2563
2683
|
titleElement,
|
|
2564
|
-
trailing != null && /* @__PURE__ */
|
|
2565
|
-
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(
|
|
2566
2686
|
"div",
|
|
2567
2687
|
{
|
|
2568
2688
|
className: cn(
|
|
2569
2689
|
"-mr-1 flex shrink-0 items-center gap-1",
|
|
2570
2690
|
showActions === "hover" && "opacity-0 transition-opacity focus-within:opacity-100 group-hover:opacity-100"
|
|
2571
2691
|
),
|
|
2572
|
-
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))
|
|
2573
2693
|
}
|
|
2574
2694
|
)
|
|
2575
2695
|
]
|
|
@@ -2580,7 +2700,7 @@ function SectionHeader({ title, chevron = false, isExpanded = true, onToggle, tr
|
|
|
2580
2700
|
// src/CollapsibleSection.tsx
|
|
2581
2701
|
import { useState as useState7 } from "react";
|
|
2582
2702
|
import { Collapsible } from "@base-ui/react/collapsible";
|
|
2583
|
-
import { jsx as
|
|
2703
|
+
import { jsx as jsx50, jsxs as jsxs34 } from "react/jsx-runtime";
|
|
2584
2704
|
var OPEN = "open";
|
|
2585
2705
|
var CLOSED = "closed";
|
|
2586
2706
|
function readStored(key) {
|
|
@@ -2607,14 +2727,14 @@ function CollapsibleSection({ title, defaultOpen = true, open: openProp, onOpenC
|
|
|
2607
2727
|
writeStored(storageKey, next);
|
|
2608
2728
|
onOpenChange?.(next);
|
|
2609
2729
|
};
|
|
2610
|
-
return /* @__PURE__ */
|
|
2611
|
-
/* @__PURE__ */
|
|
2612
|
-
/* @__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(
|
|
2613
2733
|
Collapsible.Panel,
|
|
2614
2734
|
{
|
|
2615
2735
|
hiddenUntilFound: true,
|
|
2616
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",
|
|
2617
|
-
children: /* @__PURE__ */
|
|
2737
|
+
children: /* @__PURE__ */ jsx50("div", { className: cn("flex flex-col", contentClassName), children })
|
|
2618
2738
|
}
|
|
2619
2739
|
)
|
|
2620
2740
|
] });
|
|
@@ -2622,9 +2742,9 @@ function CollapsibleSection({ title, defaultOpen = true, open: openProp, onOpenC
|
|
|
2622
2742
|
|
|
2623
2743
|
// src/Tabs.tsx
|
|
2624
2744
|
import { Tabs as BaseTabs } from "@base-ui/react/tabs";
|
|
2625
|
-
import { jsx as
|
|
2745
|
+
import { jsx as jsx51, jsxs as jsxs35 } from "react/jsx-runtime";
|
|
2626
2746
|
function Tabs({ tabs, active, onChange, size = "default", className, ...aria }) {
|
|
2627
|
-
return /* @__PURE__ */
|
|
2747
|
+
return /* @__PURE__ */ jsx51(
|
|
2628
2748
|
BaseTabs.Root,
|
|
2629
2749
|
{
|
|
2630
2750
|
value: active,
|
|
@@ -2632,14 +2752,14 @@ function Tabs({ tabs, active, onChange, size = "default", className, ...aria })
|
|
|
2632
2752
|
if (details.reason === "none") onChange(value);
|
|
2633
2753
|
},
|
|
2634
2754
|
className,
|
|
2635
|
-
children: /* @__PURE__ */
|
|
2755
|
+
children: /* @__PURE__ */ jsx51(
|
|
2636
2756
|
BaseTabs.List,
|
|
2637
2757
|
{
|
|
2638
2758
|
activateOnFocus: true,
|
|
2639
2759
|
"aria-label": aria["aria-label"],
|
|
2640
2760
|
"aria-labelledby": aria["aria-labelledby"],
|
|
2641
2761
|
className: "flex items-center gap-2",
|
|
2642
|
-
children: tabs.map((tab) => /* @__PURE__ */
|
|
2762
|
+
children: tabs.map((tab) => /* @__PURE__ */ jsxs35(
|
|
2643
2763
|
BaseTabs.Tab,
|
|
2644
2764
|
{
|
|
2645
2765
|
value: tab.id,
|
|
@@ -2652,9 +2772,9 @@ function Tabs({ tabs, active, onChange, size = "default", className, ...aria })
|
|
|
2652
2772
|
),
|
|
2653
2773
|
children: [
|
|
2654
2774
|
tab.icon,
|
|
2655
|
-
/* @__PURE__ */
|
|
2775
|
+
/* @__PURE__ */ jsxs35("span", { className: "flex items-baseline", children: [
|
|
2656
2776
|
tab.label,
|
|
2657
|
-
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
|
|
2658
2778
|
] })
|
|
2659
2779
|
]
|
|
2660
2780
|
},
|
|
@@ -2667,10 +2787,10 @@ function Tabs({ tabs, active, onChange, size = "default", className, ...aria })
|
|
|
2667
2787
|
}
|
|
2668
2788
|
|
|
2669
2789
|
// src/Toast.tsx
|
|
2670
|
-
import { createContext as
|
|
2790
|
+
import { createContext as createContext4, useContext as useContext4, useMemo as useMemo4 } from "react";
|
|
2671
2791
|
import { Toast as BaseToast } from "@base-ui/react/toast";
|
|
2672
2792
|
import { IconAlertCircle as IconAlertCircle2, IconCircleCheck, IconCircleX } from "@tabler/icons-react";
|
|
2673
|
-
import { jsx as
|
|
2793
|
+
import { jsx as jsx52, jsxs as jsxs36 } from "react/jsx-runtime";
|
|
2674
2794
|
var SURFACE_STYLES = {
|
|
2675
2795
|
success: "bg-success-muted signal:bg-bg-inset signal:border signal:border-border-default signal:shadow-md",
|
|
2676
2796
|
brand: "bg-accent-muted signal:bg-bg-inset signal:border signal:border-border-default signal:shadow-md",
|
|
@@ -2706,19 +2826,19 @@ var pillClassName = (type, hasAction, className) => cn(
|
|
|
2706
2826
|
);
|
|
2707
2827
|
function LeadingIcon({ type }) {
|
|
2708
2828
|
const Icon = ICONS[type];
|
|
2709
|
-
return /* @__PURE__ */
|
|
2829
|
+
return /* @__PURE__ */ jsx52(Icon, { size: 16, stroke: 1.5, className: cn("text-text-primary shrink-0", ICON_STYLES[type]) });
|
|
2710
2830
|
}
|
|
2711
2831
|
function Toast({ label, type = "neutral", leadingIcon = true, actionLabel, onAction, className }) {
|
|
2712
2832
|
const hasAction = !!(actionLabel && onAction);
|
|
2713
|
-
return /* @__PURE__ */
|
|
2714
|
-
/* @__PURE__ */
|
|
2715
|
-
leadingIcon && /* @__PURE__ */
|
|
2716
|
-
/* @__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 })
|
|
2717
2837
|
] }),
|
|
2718
|
-
hasAction && /* @__PURE__ */
|
|
2838
|
+
hasAction && /* @__PURE__ */ jsx52(Button, { variant: "outlined", size: "small", onClick: onAction, children: actionLabel })
|
|
2719
2839
|
] });
|
|
2720
2840
|
}
|
|
2721
|
-
var ToastContext =
|
|
2841
|
+
var ToastContext = createContext4(null);
|
|
2722
2842
|
var VISIBLE_TOASTS = 3;
|
|
2723
2843
|
function ToastProvider({ children }) {
|
|
2724
2844
|
const manager = useMemo4(() => BaseToast.createToastManager(), []);
|
|
@@ -2736,9 +2856,9 @@ function ToastProvider({ children }) {
|
|
|
2736
2856
|
}),
|
|
2737
2857
|
[manager]
|
|
2738
2858
|
);
|
|
2739
|
-
return /* @__PURE__ */
|
|
2859
|
+
return /* @__PURE__ */ jsx52(ToastContext.Provider, { value, children: /* @__PURE__ */ jsxs36(BaseToast.Provider, { toastManager: manager, limit: VISIBLE_TOASTS, children: [
|
|
2740
2860
|
children,
|
|
2741
|
-
/* @__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, {}) }) })
|
|
2742
2862
|
] }) });
|
|
2743
2863
|
}
|
|
2744
2864
|
function ToastList() {
|
|
@@ -2746,25 +2866,25 @@ function ToastList() {
|
|
|
2746
2866
|
return toasts.map((toast) => {
|
|
2747
2867
|
const type = toast.type ?? "neutral";
|
|
2748
2868
|
const { leadingIcon = true, actionLabel, onAction } = toast.data ?? {};
|
|
2749
|
-
return /* @__PURE__ */
|
|
2869
|
+
return /* @__PURE__ */ jsxs36(
|
|
2750
2870
|
BaseToast.Root,
|
|
2751
2871
|
{
|
|
2752
2872
|
toast,
|
|
2753
2873
|
swipeDirection: ["left", "down"],
|
|
2754
2874
|
className: pillClassName(type, !!actionLabel, "pointer-events-auto data-[limited]:hidden"),
|
|
2755
2875
|
children: [
|
|
2756
|
-
/* @__PURE__ */
|
|
2757
|
-
leadingIcon && /* @__PURE__ */
|
|
2758
|
-
/* @__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 })
|
|
2759
2879
|
] }),
|
|
2760
|
-
actionLabel && /* @__PURE__ */
|
|
2880
|
+
actionLabel && /* @__PURE__ */ jsx52(
|
|
2761
2881
|
BaseToast.Action,
|
|
2762
2882
|
{
|
|
2763
2883
|
onClick: () => {
|
|
2764
2884
|
onAction?.();
|
|
2765
2885
|
close(toast.id);
|
|
2766
2886
|
},
|
|
2767
|
-
render: /* @__PURE__ */
|
|
2887
|
+
render: /* @__PURE__ */ jsx52(Button, { variant: "outlined", size: "small", children: actionLabel })
|
|
2768
2888
|
}
|
|
2769
2889
|
)
|
|
2770
2890
|
]
|
|
@@ -2774,7 +2894,7 @@ function ToastList() {
|
|
|
2774
2894
|
});
|
|
2775
2895
|
}
|
|
2776
2896
|
function useToast() {
|
|
2777
|
-
const ctx =
|
|
2897
|
+
const ctx = useContext4(ToastContext);
|
|
2778
2898
|
if (!ctx) throw new Error("useToast must be used within ToastProvider");
|
|
2779
2899
|
return ctx;
|
|
2780
2900
|
}
|
|
@@ -2805,6 +2925,8 @@ export {
|
|
|
2805
2925
|
EnterHint,
|
|
2806
2926
|
Field,
|
|
2807
2927
|
FieldLine,
|
|
2928
|
+
FilePicker,
|
|
2929
|
+
Form,
|
|
2808
2930
|
INLINE_CHIP_CLASSES,
|
|
2809
2931
|
INLINE_CHIP_TONE_CLASSES,
|
|
2810
2932
|
IconButton,
|