@parallelworks/ui 0.16.0 → 0.18.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/LICENSE +202 -21
- package/dist/chunks/{CodePreviewEditor-DuMZMA_k.js → CodePreviewEditor-4lx3kE-w.js} +2 -2
- package/dist/chunks/{CreateModal-B7smkHkv.js → CreateModal-BY6DLmur.js} +11 -11
- package/dist/chunks/{lib-CUTRDpa6.js → FieldWrapper-Bef01EWO.js} +49 -48
- package/dist/chunks/{Monaco-BXDH2jVj.js → Monaco-C1POOdVv.js} +485 -172
- package/dist/chunks/{PageHeader-CoZWF0pJ.js → PageHeader-l49p1nM9.js} +145 -82
- package/dist/chunks/{Provider-CbFVFB7O.js → Provider-Ghua9PkN.js} +34 -6
- package/dist/chunks/{StatusBadge-zvEtK16a.js → StatusBadge-C1Blx_cW.js} +23 -6
- package/dist/chunks/{SwitchToggle-3V836Cn7.js → SwitchToggle-CHPP8uZQ.js} +17 -14
- package/dist/chunks/{Table-CutP1bRt.js → Table-4OHjdKdO.js} +2 -2
- package/dist/chunks/{Tooltip-n9w7Tkt1.js → Tooltip-Crxo_eU_.js} +3 -3
- package/dist/chunks/{editor-Ko3zX22Y.js → editor-9_uVtUyy.js} +4 -4
- package/dist/chunks/{list-CduoUsMW.js → list-qrojZZNv.js} +146 -33
- package/dist/components/AddMenu.d.ts +1 -0
- package/dist/components/Avatar.d.ts +13 -0
- package/dist/components/Button.d.ts +2 -1
- package/dist/components/Dropdown.d.ts +2 -0
- package/dist/components/Provider.d.ts +59 -2
- package/dist/components/SectionHeader.d.ts +3 -1
- package/dist/components/StatusBadge.d.ts +7 -2
- package/dist/components/relativeTime.d.ts +15 -0
- package/dist/editor/index.js +1 -1
- package/dist/editor/usesGitlab.d.ts +97 -0
- package/dist/file-explorer/index.js +275 -274
- package/dist/file-explorer/lib/paging.d.ts +27 -28
- package/dist/file-explorer/lib/types.d.ts +0 -1
- package/dist/file-explorer/lib/utils.d.ts +16 -5
- package/dist/form/FieldWrapper.d.ts +2 -1
- package/dist/form/Form.d.ts +3 -1
- package/dist/form/index.js +23 -21
- package/dist/form/types/fieldComponentTypes.d.ts +1 -0
- package/dist/form/types/fieldTypes.d.ts +4 -4
- package/dist/form/types/workflow-schema.d.ts +38 -0
- package/dist/form/useParsedOpts.d.ts +1 -1
- package/dist/icons.d.ts +1 -1
- package/dist/icons.js +3 -3
- package/dist/index.d.ts +5 -2
- package/dist/index.js +49 -18
- package/dist/list/ListPage.d.ts +3 -1
- package/dist/list/ListPager.d.ts +3 -1
- package/dist/list/ListTable.d.ts +2 -1
- package/dist/list/RowContextMenu.d.ts +9 -9
- package/dist/list/UserHoverCard.d.ts +45 -0
- package/dist/list/index.d.ts +2 -1
- package/dist/list/index.js +3 -3
- package/dist/list/listView.d.ts +1 -1
- package/dist/logviewer/index.js +7 -7
- package/dist/styles/Geist-Variable.woff2 +0 -0
- package/dist/styles/GeistMono-Variable.woff2 +0 -0
- package/dist/styles/base.css +57 -0
- package/dist/styles/fonts.css +15 -0
- package/dist/styles/theme.css +6 -40
- package/dist/styles.css +1 -1
- package/dist/workflow/DependencyGraph.d.ts +2 -0
- package/dist/workflow/index.d.ts +1 -0
- package/dist/workflow/index.js +10 -9
- package/dist/workflow/types.d.ts +5 -0
- package/package.json +12 -11
- package/dist/chunks/{BareModal-BqroLbZ5.js → BareModal-BtRiQezg.js} +1 -1
|
@@ -1,14 +1,14 @@
|
|
|
1
|
+
import { a as usePersistedState, n as useLink, r as useNavigation, u as useStrings } from "./Provider-Ghua9PkN.js";
|
|
2
|
+
import { T as Avatar, _ as useRowMenuActive, c as PageHeader, f as rowContextMenuProps, u as MoreButton } from "./PageHeader-l49p1nM9.js";
|
|
1
3
|
import { CheckIcon, ChevronDownIcon, ChevronLeftIcon, ChevronRightIcon, ChevronUpIcon, DisplayIcon, ErrorIcon, FilterIcon, MenuIcon, SearchIcon, XIcon } from "../icons.js";
|
|
2
|
-
import {
|
|
3
|
-
import { n as
|
|
4
|
-
import { _ as useRowMenuActive, c as PageHeader, p as rowContextMenuProps, u as MoreButton } from "./PageHeader-CoZWF0pJ.js";
|
|
5
|
-
import { n as Table } from "./Table-CutP1bRt.js";
|
|
4
|
+
import { n as TOOLTIP_ID, r as TooltipInfo } from "./Tooltip-Crxo_eU_.js";
|
|
5
|
+
import { n as Table } from "./Table-4OHjdKdO.js";
|
|
6
6
|
import cx from "classnames";
|
|
7
|
-
import { Fragment,
|
|
8
|
-
import {
|
|
7
|
+
import { Children, Fragment, cloneElement, createContext, isValidElement, useCallback, useContext, useEffect, useLayoutEffect, useMemo, useRef, useState } from "react";
|
|
8
|
+
import { useLocalStorage } from "usehooks-ts";
|
|
9
|
+
import { Fragment as Fragment$1, jsx, jsxs } from "react/jsx-runtime";
|
|
9
10
|
import { createPortal } from "react-dom";
|
|
10
11
|
import { Menu, MenuButton, MenuItem, MenuItems } from "@headlessui/react";
|
|
11
|
-
import { useLocalStorage } from "usehooks-ts";
|
|
12
12
|
//#region src/list/ActionToolbar.tsx
|
|
13
13
|
var OverflowMenuContext = createContext(false);
|
|
14
14
|
/** Omits data-tooltip-content when absent — react-tooltip treats an explicit undefined as an empty tooltip anchor. */
|
|
@@ -20,7 +20,7 @@ function tipProps(content, place) {
|
|
|
20
20
|
};
|
|
21
21
|
}
|
|
22
22
|
function ToolbarItemView({ item }) {
|
|
23
|
-
if ("element" in item) return /* @__PURE__ */ jsx(Fragment, { children: item.element });
|
|
23
|
+
if ("element" in item) return /* @__PURE__ */ jsx(Fragment$1, { children: item.element });
|
|
24
24
|
return /* @__PURE__ */ jsx(ToolbarButton, { action: item });
|
|
25
25
|
}
|
|
26
26
|
function ToolbarButton({ action }) {
|
|
@@ -30,7 +30,7 @@ function ToolbarButton({ action }) {
|
|
|
30
30
|
const className = cx("inline-flex items-center gap-x-0.5 h-9 px-2 rounded-md text-[13.5px] uppercase font-semibold transition-colors whitespace-nowrap", "bg-(--theme-element) text-(--theme-element-text)", action.disabled ? "opacity-50 cursor-not-allowed" : "cursor-pointer hover:bg-(--theme-element-hover)");
|
|
31
31
|
const tooltipProps = tipProps(action.disabled ? action.disabledTooltip : action.enabledTooltip, "bottom");
|
|
32
32
|
const Icon = action.icon;
|
|
33
|
-
const content = /* @__PURE__ */ jsxs(Fragment, { children: [/* @__PURE__ */ jsx("div", {
|
|
33
|
+
const content = /* @__PURE__ */ jsxs(Fragment$1, { children: [/* @__PURE__ */ jsx("div", {
|
|
34
34
|
className: "h-6 flex items-center",
|
|
35
35
|
children: /* @__PURE__ */ jsx(Icon, { className: cx("w-auto", action.iconClassName) })
|
|
36
36
|
}), action.label] });
|
|
@@ -64,7 +64,7 @@ function OverflowRow({ item }) {
|
|
|
64
64
|
const Icon = item.icon;
|
|
65
65
|
const className = cx("flex w-full items-center gap-x-1 px-4 py-2 text-[13px] uppercase font-semibold link hover:theme-hover", item.disabled && "opacity-50 cursor-not-allowed");
|
|
66
66
|
const tooltipProps = tipProps(item.disabled ? item.disabledTooltip : item.enabledTooltip, "left");
|
|
67
|
-
const content = /* @__PURE__ */ jsxs(Fragment, { children: [/* @__PURE__ */ jsx("div", {
|
|
67
|
+
const content = /* @__PURE__ */ jsxs(Fragment$1, { children: [/* @__PURE__ */ jsx("div", {
|
|
68
68
|
className: "w-5 h-6 flex items-center",
|
|
69
69
|
children: /* @__PURE__ */ jsx(Icon, { className: cx(item.iconClassName) })
|
|
70
70
|
}), item.label] });
|
|
@@ -106,7 +106,7 @@ function OverflowMenu({ items }) {
|
|
|
106
106
|
className: "z-50 min-w-56 rounded-md border theme-border bg-(--theme-app-bg) shadow-lg py-1 focus:outline-none",
|
|
107
107
|
children: /* @__PURE__ */ jsx(OverflowMenuContext.Provider, {
|
|
108
108
|
value: true,
|
|
109
|
-
children: items.map((item) => "element" in item ? /* @__PURE__ */ jsx(Fragment
|
|
109
|
+
children: items.map((item) => "element" in item ? /* @__PURE__ */ jsx(Fragment, { children: item.element }, item.key) : /* @__PURE__ */ jsx(OverflowRow, { item }, item.key))
|
|
110
110
|
})
|
|
111
111
|
})]
|
|
112
112
|
});
|
|
@@ -177,7 +177,7 @@ function ActionToolbar({ groups, right = [], sticky = false }) {
|
|
|
177
177
|
className: cx("flex items-center gap-2.5", sticky && cx("sticky top-10 z-10 bg-(--theme-app-bg)", "py-1.5")),
|
|
178
178
|
children: [visibleGroups.length > 0 && /* @__PURE__ */ jsx("div", {
|
|
179
179
|
className: "flex items-center gap-2.5 shrink-0",
|
|
180
|
-
children: visibleGroups.map((group, i) => /* @__PURE__ */ jsxs(Fragment
|
|
180
|
+
children: visibleGroups.map((group, i) => /* @__PURE__ */ jsxs(Fragment, { children: [i > 0 && /* @__PURE__ */ jsx("div", { className: "w-px h-5 bg-(--theme-border)" }), /* @__PURE__ */ jsx("div", {
|
|
181
181
|
className: "flex items-center gap-1",
|
|
182
182
|
children: group.map((item) => /* @__PURE__ */ jsx(ToolbarItemView, { item }, item.key))
|
|
183
183
|
})] }, group[0]?.key ?? i))
|
|
@@ -203,14 +203,15 @@ var listTableFixedProps = {
|
|
|
203
203
|
...listTableProps,
|
|
204
204
|
className: listTableProps.className.replace("table-auto", "table-fixed")
|
|
205
205
|
};
|
|
206
|
-
function NameCell({ icon, name, subtitle, href, badge }) {
|
|
206
|
+
function NameCell({ icon, name, subtitle, href, badge, title }) {
|
|
207
207
|
const Link = useLink();
|
|
208
|
-
const inner = /* @__PURE__ */ jsxs(Fragment, { children: [icon, /* @__PURE__ */ jsxs("div", {
|
|
208
|
+
const inner = /* @__PURE__ */ jsxs(Fragment$1, { children: [icon, /* @__PURE__ */ jsxs("div", {
|
|
209
209
|
className: "min-w-0",
|
|
210
210
|
children: [/* @__PURE__ */ jsxs("div", {
|
|
211
211
|
className: "flex min-w-0 items-center gap-1.5",
|
|
212
212
|
children: [/* @__PURE__ */ jsx("div", {
|
|
213
213
|
className: cx(NAME_TEXT, href && "group-hover/namecell:text-(--theme-link)"),
|
|
214
|
+
title,
|
|
214
215
|
children: name
|
|
215
216
|
}), badge]
|
|
216
217
|
}), subtitle && /* @__PURE__ */ jsx("div", {
|
|
@@ -331,7 +332,7 @@ function ListActionsHeader({ view, actionCount = 0, className }) {
|
|
|
331
332
|
width,
|
|
332
333
|
minWidth: width
|
|
333
334
|
},
|
|
334
|
-
className: cx("py-2 text-right @max-[43rem]:w-[52px]! @max-[43rem]:min-w-[52px]!", className),
|
|
335
|
+
className: cx("relative py-2 text-right @max-[43rem]:w-[52px]! @max-[43rem]:min-w-[52px]!", className),
|
|
335
336
|
children: /* @__PURE__ */ jsx("span", {
|
|
336
337
|
className: "sr-only",
|
|
337
338
|
children: "Actions"
|
|
@@ -401,7 +402,7 @@ function ListPage({ section = "main", shellPadded, embedded = false, breadcrumbs
|
|
|
401
402
|
})]
|
|
402
403
|
});
|
|
403
404
|
}
|
|
404
|
-
function ListRow({ href, items, goTo, openMenu, pinnedActions, selected, selectionActive, onRowSelect, leading, className, children }) {
|
|
405
|
+
function ListRow({ href, onActivate, items, goTo, openMenu, pinnedActions, selected, selectionActive, onRowSelect, leading, className, children }) {
|
|
405
406
|
const { active: menuActive, openMenu: openRowMenu } = useRowMenuActive(openMenu);
|
|
406
407
|
const { show: showActions, always: alwaysShowActions, columnClasses } = useContext(RowActionsContext);
|
|
407
408
|
const styledCells = Children.toArray(children).map((child, i) => {
|
|
@@ -417,11 +418,12 @@ function ListRow({ href, items, goTo, openMenu, pinnedActions, selected, selecti
|
|
|
417
418
|
return;
|
|
418
419
|
}
|
|
419
420
|
if (href) goTo(href);
|
|
421
|
+
else onActivate?.();
|
|
420
422
|
};
|
|
421
423
|
const pinnedLabels = new Set((pinnedActions ?? []).map((a) => a.label));
|
|
422
424
|
const hasOverflowItems = items.some((item) => item.kind !== "divider" && (item.kind === "submenu" || !pinnedLabels.has(item.label)));
|
|
423
425
|
return /* @__PURE__ */ jsxs("tr", {
|
|
424
|
-
className: cx("group", selected ? "bg-blue-500/5" : menuActive ? "theme-hover" : "hover:theme-hover", (href || selectionActive) && "cursor-pointer", className),
|
|
426
|
+
className: cx("group", selected ? "bg-blue-500/5" : menuActive ? "theme-hover" : "hover:theme-hover", (href || onActivate || selectionActive) && "cursor-pointer", className),
|
|
425
427
|
onClick: handleRowClick,
|
|
426
428
|
...rowContextMenuProps(openRowMenu, items),
|
|
427
429
|
children: [
|
|
@@ -460,7 +462,7 @@ function ListRow({ href, items, goTo, openMenu, pinnedActions, selected, selecti
|
|
|
460
462
|
}
|
|
461
463
|
/** Name column min-width is by role, not position, so a leading checkbox doesn't shift it. */
|
|
462
464
|
function ListColumns({ view }) {
|
|
463
|
-
return /* @__PURE__ */ jsxs(Fragment, { children: [view.visibleColumns.map((col, i) => /* @__PURE__ */ jsx(Table.Header, {
|
|
465
|
+
return /* @__PURE__ */ jsxs(Fragment$1, { children: [view.visibleColumns.map((col, i) => /* @__PURE__ */ jsx(Table.Header, {
|
|
464
466
|
caps: false,
|
|
465
467
|
className: cx(col.headerClassName, view.columnClasses[i]),
|
|
466
468
|
style: col.alwaysVisible ? { minWidth: 200 } : void 0,
|
|
@@ -518,16 +520,16 @@ function useListView({ storageKey, sharedFiltersKey, columns, groupBys = [], def
|
|
|
518
520
|
const defaultOrderByValue = isFavorite ? DEFAULT_ORDER : defaultOrderBy ?? orderBys[0]?.value ?? "";
|
|
519
521
|
const defaultHiddenKeys = useMemo(() => columns.filter((c) => c.defaultHidden && !c.alwaysVisible).map((c) => c.key), [columns]);
|
|
520
522
|
const defaultPinnedKeys = useMemo(() => actions.filter((a) => a.defaultPinned).map((a) => a.key), [actions]);
|
|
521
|
-
const [hiddenKeys, setHiddenKeys] =
|
|
522
|
-
const [pinnedKeys, setPinnedKeys] =
|
|
523
|
-
const [groupBy, setGroupBy] =
|
|
524
|
-
const [showColumnHeaders, setShowColumnHeaders] =
|
|
525
|
-
const [showActions, setShowActions] =
|
|
526
|
-
const [alwaysShowActions, setAlwaysShowActions] =
|
|
527
|
-
const [orderBy, setOrderBy] =
|
|
528
|
-
const [orderDir, setOrderDir] =
|
|
529
|
-
const [localFilters, setLocalFilters] =
|
|
530
|
-
const [sharedFilters, setSharedFilters] =
|
|
523
|
+
const [hiddenKeys, setHiddenKeys] = usePersistedState(`${storageKey}:hiddenColumns`, defaultHiddenKeys);
|
|
524
|
+
const [pinnedKeys, setPinnedKeys] = usePersistedState(`${storageKey}:pinnedActions`, defaultPinnedKeys);
|
|
525
|
+
const [groupBy, setGroupBy] = usePersistedState(`${storageKey}:groupBy`, defaultGroupByValue);
|
|
526
|
+
const [showColumnHeaders, setShowColumnHeaders] = usePersistedState(`${storageKey}:showColumnHeaders`, defaultShowColumnHeaders);
|
|
527
|
+
const [showActions, setShowActions] = usePersistedState(`${storageKey}:showActions`, defaultShowActions);
|
|
528
|
+
const [alwaysShowActions, setAlwaysShowActions] = usePersistedState(`${storageKey}:alwaysShowActions`, false);
|
|
529
|
+
const [orderBy, setOrderBy] = usePersistedState(`${storageKey}:orderBy`, defaultOrderByValue);
|
|
530
|
+
const [orderDir, setOrderDir] = usePersistedState(`${storageKey}:orderDir`, "asc");
|
|
531
|
+
const [localFilters, setLocalFilters] = usePersistedState(`${storageKey}:filters`, {});
|
|
532
|
+
const [sharedFilters, setSharedFilters] = usePersistedState(`${sharedFiltersKey ?? storageKey}:sharedFilters`, {});
|
|
531
533
|
const sharedKeys = useMemo(() => new Set(facets.filter((f) => f.shared).map((f) => f.key)), [facets]);
|
|
532
534
|
const filters = useMemo(() => {
|
|
533
535
|
if (sharedKeys.size === 0) return localFilters;
|
|
@@ -741,7 +743,7 @@ function AnchoredPopover({ icon, label, active, shortcut, panelClassName, childr
|
|
|
741
743
|
window.addEventListener("keydown", onKey);
|
|
742
744
|
return () => window.removeEventListener("keydown", onKey);
|
|
743
745
|
}, [shortcut, open]);
|
|
744
|
-
return /* @__PURE__ */ jsxs(Fragment, { children: [/* @__PURE__ */ jsxs("button", {
|
|
746
|
+
return /* @__PURE__ */ jsxs(Fragment$1, { children: [/* @__PURE__ */ jsxs("button", {
|
|
745
747
|
ref: btnRef,
|
|
746
748
|
type: "button",
|
|
747
749
|
onClick: () => pos ? close() : open(),
|
|
@@ -984,7 +986,7 @@ function FilterMenuBody({ view }) {
|
|
|
984
986
|
const scheduleClose = () => {
|
|
985
987
|
closeTimer.current = setTimeout(() => setOpenKey(null), 160);
|
|
986
988
|
};
|
|
987
|
-
return /* @__PURE__ */ jsxs(Fragment, { children: [/* @__PURE__ */ jsxs("div", {
|
|
989
|
+
return /* @__PURE__ */ jsxs(Fragment$1, { children: [/* @__PURE__ */ jsxs("div", {
|
|
988
990
|
className: "flex items-center justify-between px-3 py-1",
|
|
989
991
|
children: [/* @__PURE__ */ jsx("span", {
|
|
990
992
|
className: "text-[11px] font-medium uppercase tracking-wide text-(--theme-muted-text-color)",
|
|
@@ -1184,7 +1186,7 @@ var LIST_PAGE_SIZES = [
|
|
|
1184
1186
|
200
|
|
1185
1187
|
];
|
|
1186
1188
|
/** Footer pager bar for paginated new-nav lists: "{start}–{end} of {total}" with prev/next. Renders nothing for a single page. */
|
|
1187
|
-
function ListPager({ page, pageSize, total, onPageChange, pageSizes = LIST_PAGE_SIZES, onPageSizeChange }) {
|
|
1189
|
+
function ListPager({ page, pageSize, total, onPageChange, pageSizes = LIST_PAGE_SIZES, onPageSizeChange, hasNext }) {
|
|
1188
1190
|
const t = useStrings().list;
|
|
1189
1191
|
const pageCount = Math.max(1, Math.ceil(total / pageSize));
|
|
1190
1192
|
const start = page * pageSize + 1;
|
|
@@ -1220,7 +1222,7 @@ function ListPager({ page, pageSize, total, onPageChange, pageSizes = LIST_PAGE_
|
|
|
1220
1222
|
}), /* @__PURE__ */ jsx("button", {
|
|
1221
1223
|
type: "button",
|
|
1222
1224
|
"aria-label": t.paginationNext,
|
|
1223
|
-
disabled: page >= pageCount - 1,
|
|
1225
|
+
disabled: hasNext === void 0 ? page >= pageCount - 1 : !hasNext,
|
|
1224
1226
|
onClick: () => onPageChange(page + 1),
|
|
1225
1227
|
className: cx(listControlButtonClasses, "disabled:opacity-40 disabled:pointer-events-none"),
|
|
1226
1228
|
children: /* @__PURE__ */ jsx(ChevronRightIcon, { className: "w-3.5 h-3.5" })
|
|
@@ -1295,4 +1297,115 @@ function HoverCardSurface({ x, y, widthClassName, padded = true, relayoutKey, on
|
|
|
1295
1297
|
}), document.querySelector(".ds-root") ?? document.body);
|
|
1296
1298
|
}
|
|
1297
1299
|
//#endregion
|
|
1298
|
-
|
|
1300
|
+
//#region src/list/UserHoverCard.tsx
|
|
1301
|
+
/** Opens `card` after a short hover or on focus of `children`. */
|
|
1302
|
+
function HoverCardTrigger({ className, children, card }) {
|
|
1303
|
+
const { triggerRef, coords, scheduleOpen, scheduleClose, keepOpen } = useHoverCard();
|
|
1304
|
+
return /* @__PURE__ */ jsxs("span", {
|
|
1305
|
+
ref: triggerRef,
|
|
1306
|
+
role: "none",
|
|
1307
|
+
className,
|
|
1308
|
+
onMouseEnter: scheduleOpen,
|
|
1309
|
+
onMouseLeave: scheduleClose,
|
|
1310
|
+
onFocus: scheduleOpen,
|
|
1311
|
+
onBlur: scheduleClose,
|
|
1312
|
+
children: [children, coords && card({
|
|
1313
|
+
x: coords.x,
|
|
1314
|
+
y: coords.y,
|
|
1315
|
+
onKeepOpen: keepOpen,
|
|
1316
|
+
onLeave: scheduleClose
|
|
1317
|
+
})]
|
|
1318
|
+
});
|
|
1319
|
+
}
|
|
1320
|
+
function UserHoverCard({ x, y, onKeepOpen, onLeave, username, name, avatarSrc, badge, href, linkComponent, loading = false, relayoutKey, children }) {
|
|
1321
|
+
const strings = useStrings();
|
|
1322
|
+
const SlotLink = useLink();
|
|
1323
|
+
const Link = linkComponent ?? SlotLink;
|
|
1324
|
+
const displayName = name || username;
|
|
1325
|
+
const header = /* @__PURE__ */ jsxs(Fragment$1, { children: [/* @__PURE__ */ jsx(Avatar, {
|
|
1326
|
+
src: avatarSrc,
|
|
1327
|
+
name: displayName,
|
|
1328
|
+
size: "lg",
|
|
1329
|
+
className: "shrink-0"
|
|
1330
|
+
}), /* @__PURE__ */ jsxs("div", {
|
|
1331
|
+
className: "min-w-0",
|
|
1332
|
+
children: [/* @__PURE__ */ jsxs("div", {
|
|
1333
|
+
className: "flex items-center gap-1.5",
|
|
1334
|
+
children: [/* @__PURE__ */ jsx("span", {
|
|
1335
|
+
className: "truncate text-sm font-semibold text-(--theme-app)",
|
|
1336
|
+
children: displayName
|
|
1337
|
+
}), badge && /* @__PURE__ */ jsx("span", {
|
|
1338
|
+
className: "shrink-0 rounded-full bg-(--theme-muted-panel-bg) px-1.5 py-0.5 text-[10px] font-medium leading-none text-(--theme-muted-text-color)",
|
|
1339
|
+
children: badge
|
|
1340
|
+
})]
|
|
1341
|
+
}), /* @__PURE__ */ jsx("div", {
|
|
1342
|
+
className: "truncate text-xs text-(--theme-muted-text-color)",
|
|
1343
|
+
children: username
|
|
1344
|
+
})]
|
|
1345
|
+
})] });
|
|
1346
|
+
return /* @__PURE__ */ jsxs(HoverCardSurface, {
|
|
1347
|
+
x,
|
|
1348
|
+
y,
|
|
1349
|
+
widthClassName: "w-64",
|
|
1350
|
+
relayoutKey,
|
|
1351
|
+
onKeepOpen,
|
|
1352
|
+
onLeave,
|
|
1353
|
+
children: [href ? /* @__PURE__ */ jsx(Link, {
|
|
1354
|
+
to: href,
|
|
1355
|
+
className: "flex items-center gap-3 transition-opacity hover:opacity-80",
|
|
1356
|
+
children: header
|
|
1357
|
+
}) : /* @__PURE__ */ jsx("div", {
|
|
1358
|
+
className: "flex items-center gap-3",
|
|
1359
|
+
children: header
|
|
1360
|
+
}), loading ? /* @__PURE__ */ jsxs("div", {
|
|
1361
|
+
role: "status",
|
|
1362
|
+
"aria-label": strings.loading,
|
|
1363
|
+
className: "mt-3 space-y-2 border-t border-(--theme-border) pt-3",
|
|
1364
|
+
children: [
|
|
1365
|
+
/* @__PURE__ */ jsx("div", {
|
|
1366
|
+
"aria-hidden": "true",
|
|
1367
|
+
className: "h-3 w-24 animate-pulse rounded theme-muted-panel"
|
|
1368
|
+
}),
|
|
1369
|
+
/* @__PURE__ */ jsx("div", {
|
|
1370
|
+
"aria-hidden": "true",
|
|
1371
|
+
className: "h-3 w-36 animate-pulse rounded theme-muted-panel"
|
|
1372
|
+
}),
|
|
1373
|
+
/* @__PURE__ */ jsx("span", {
|
|
1374
|
+
className: "sr-only",
|
|
1375
|
+
children: strings.loading
|
|
1376
|
+
})
|
|
1377
|
+
]
|
|
1378
|
+
}) : children ? /* @__PURE__ */ jsx("div", {
|
|
1379
|
+
className: "mt-3 space-y-2 border-t border-(--theme-border) pt-3 text-[13px]",
|
|
1380
|
+
children
|
|
1381
|
+
}) : null]
|
|
1382
|
+
});
|
|
1383
|
+
}
|
|
1384
|
+
var rowClasses = "flex gap-2 text-(--theme-muted-text-color)";
|
|
1385
|
+
/** One detail line of a hover card: a leading icon and its content. With
|
|
1386
|
+
* `onClick` the line is a button. */
|
|
1387
|
+
function HoverCardRow({ icon, children, title, align = "center", truncate = false, onClick }) {
|
|
1388
|
+
const content = /* @__PURE__ */ jsxs(Fragment$1, { children: [/* @__PURE__ */ jsx("span", {
|
|
1389
|
+
"aria-hidden": "true",
|
|
1390
|
+
className: cx("flex shrink-0 items-center [&>svg]:h-3.5 [&>svg]:w-3.5", align === "start" && "mt-0.5"),
|
|
1391
|
+
children: icon
|
|
1392
|
+
}), /* @__PURE__ */ jsx("span", {
|
|
1393
|
+
className: cx("min-w-0", truncate && "truncate"),
|
|
1394
|
+
children
|
|
1395
|
+
})] });
|
|
1396
|
+
const alignClass = align === "start" ? "items-start" : "items-center";
|
|
1397
|
+
if (onClick) return /* @__PURE__ */ jsx("button", {
|
|
1398
|
+
type: "button",
|
|
1399
|
+
title,
|
|
1400
|
+
onClick,
|
|
1401
|
+
className: cx(rowClasses, alignClass, "-mx-1 max-w-full rounded px-1 py-0.5 text-left transition-colors hover:bg-(--theme-muted-panel-bg) hover:text-(--theme-app)"),
|
|
1402
|
+
children: content
|
|
1403
|
+
});
|
|
1404
|
+
return /* @__PURE__ */ jsx("div", {
|
|
1405
|
+
title,
|
|
1406
|
+
className: cx(rowClasses, alignClass),
|
|
1407
|
+
children: content
|
|
1408
|
+
});
|
|
1409
|
+
}
|
|
1410
|
+
//#endregion
|
|
1411
|
+
export { actionsColumnWidth as A, GroupRow as C, NAME_MIN_WIDTH_PX as D, ListSkeleton as E, stickyTabsClasses as F, stickyTabsUnderHeaderClasses as I, stickyToolbarClasses as L, listTableProps as M, ActionToolbar as N, NameCell as O, ToolbarButton as P, useListNavigate as S, ListError as T, useListView as _, useHoverCard as a, ListRow as b, ListCount as c, ListDisplayMenu as d, ListFilterMenu as f, FAVORITE_ORDER as g, DEFAULT_ORDER as h, HoverCardSurface as i, listTableFixedProps as j, RowSelectCheckbox as k, ListSearchControl as l, isTextEntryContext as m, HoverCardTrigger as n, LIST_PAGE_SIZES as o, listControlButtonClasses as p, UserHoverCard as r, ListPager as s, HoverCardRow as t, useListSearch as u, ListColumns as v, ListActionsHeader as w, ListRowActionsProvider as x, ListPage as y };
|
|
@@ -0,0 +1,13 @@
|
|
|
1
|
+
export type AvatarSize = 'sm' | 'md' | 'lg' | 'xl' | '2xl';
|
|
2
|
+
export type AvatarStatus = 'online' | 'offline' | 'busy' | 'away';
|
|
3
|
+
export interface AvatarProps {
|
|
4
|
+
/** Image URL; absent or failing to load shows the initials of `name`. */
|
|
5
|
+
src?: string | null | undefined;
|
|
6
|
+
name?: string | undefined;
|
|
7
|
+
size?: AvatarSize | undefined;
|
|
8
|
+
status?: AvatarStatus | undefined;
|
|
9
|
+
className?: string | undefined;
|
|
10
|
+
}
|
|
11
|
+
/** Up to two initials: the first and last word of a name split on spaces and dots. */
|
|
12
|
+
export declare function avatarInitials(name: string | undefined): string;
|
|
13
|
+
export declare function Avatar({ src, name, size, status, className, }: AvatarProps): import("react").JSX.Element;
|
|
@@ -13,6 +13,7 @@ interface MethodButtonProps extends ButtonHTMLAttributes<HTMLButtonElement> {
|
|
|
13
13
|
label: string;
|
|
14
14
|
description?: string;
|
|
15
15
|
href?: string;
|
|
16
|
+
loading?: boolean;
|
|
16
17
|
}
|
|
17
|
-
export declare function MethodButton({ icon, label, description, href, className, ...props }: MethodButtonProps): import("react").JSX.Element;
|
|
18
|
+
export declare function MethodButton({ icon, label, description, href, loading, disabled, className, ...props }: MethodButtonProps): import("react").JSX.Element;
|
|
18
19
|
export {};
|
|
@@ -24,5 +24,7 @@ export interface IProps {
|
|
|
24
24
|
/** Label for the toggle row hiding a category's collapsible options. */
|
|
25
25
|
collapsedLabel?: (count: number) => string;
|
|
26
26
|
portalEl?: HTMLElement;
|
|
27
|
+
/** Smaller option rows and text, for dense toolbars. */
|
|
28
|
+
compact?: boolean | undefined;
|
|
27
29
|
}
|
|
28
30
|
export default function Dropdown(props: IProps): import("react").JSX.Element;
|
|
@@ -1,4 +1,5 @@
|
|
|
1
|
-
import type { ReactNode } from 'react';
|
|
1
|
+
import type { Dispatch, ReactNode, SetStateAction } from 'react';
|
|
2
|
+
import type { RunLink } from '../workflow/types.js';
|
|
2
3
|
export type UIToastId = string | number;
|
|
3
4
|
export interface UIToastOptions {
|
|
4
5
|
toastId?: UIToastId;
|
|
@@ -54,6 +55,7 @@ export interface UIStrings {
|
|
|
54
55
|
create: string;
|
|
55
56
|
remove: string;
|
|
56
57
|
sort: string;
|
|
58
|
+
userAvatar: string;
|
|
57
59
|
};
|
|
58
60
|
dropdown: {
|
|
59
61
|
select: (type: string) => string;
|
|
@@ -321,7 +323,15 @@ export interface UIStrings {
|
|
|
321
323
|
readOnlyDescription: string;
|
|
322
324
|
readOnlyForced: string;
|
|
323
325
|
};
|
|
326
|
+
time: {
|
|
327
|
+
now: string;
|
|
328
|
+
minutes: (n: number) => string;
|
|
329
|
+
hours: (n: number) => string;
|
|
330
|
+
days: (n: number) => string;
|
|
331
|
+
years: (n: number) => string;
|
|
332
|
+
};
|
|
324
333
|
list: {
|
|
334
|
+
copyMenu: string;
|
|
325
335
|
copy: (label: string) => string;
|
|
326
336
|
copied: (label: string) => string;
|
|
327
337
|
couldntCopy: (label: string) => string;
|
|
@@ -380,6 +390,7 @@ export interface RunFileResult {
|
|
|
380
390
|
isLoading: boolean;
|
|
381
391
|
error: unknown;
|
|
382
392
|
}
|
|
393
|
+
export type PersistedStateHook = <T>(key: string, defaultValue: T) => [T, Dispatch<SetStateAction<T>>];
|
|
383
394
|
export interface UIData {
|
|
384
395
|
/**
|
|
385
396
|
* Host-bound hook resolving a file in a run's artifact tree (logs, scripts).
|
|
@@ -406,6 +417,49 @@ export interface UIData {
|
|
|
406
417
|
}) => Promise<{
|
|
407
418
|
error?: string;
|
|
408
419
|
}>;
|
|
420
|
+
usePersistedState: PersistedStateHook;
|
|
421
|
+
/**
|
|
422
|
+
* Repository completions for `uses:`, bound by the host because the credential
|
|
423
|
+
* lives on the platform. Absent, those completions no-op.
|
|
424
|
+
*/
|
|
425
|
+
repoSuggestions?: {
|
|
426
|
+
refs: (repo: string) => Promise<RepoRef[]>;
|
|
427
|
+
files: (repo: string, ref: string, path: string) => Promise<RepoEntry[]>;
|
|
428
|
+
file: (repo: string, ref: string, path: string) => Promise<string>;
|
|
429
|
+
repos: (owner: string) => Promise<RepoSummary[]>;
|
|
430
|
+
gitlabProjects: (search: string, host?: string) => Promise<GitlabProject[]>;
|
|
431
|
+
owners: (provider: 'github' | 'gitlab', search: string, host?: string) => Promise<RepoOwner[]>;
|
|
432
|
+
};
|
|
433
|
+
}
|
|
434
|
+
/** One branch, tag or commit a `uses:` reference can name. */
|
|
435
|
+
export interface RepoRef {
|
|
436
|
+
name: string;
|
|
437
|
+
kind: string;
|
|
438
|
+
detail: string;
|
|
439
|
+
}
|
|
440
|
+
/** One repository in an owner listing. */
|
|
441
|
+
export interface RepoSummary {
|
|
442
|
+
name: string;
|
|
443
|
+
description: string;
|
|
444
|
+
private: boolean;
|
|
445
|
+
}
|
|
446
|
+
/** One account, organization or group a repository can live under. */
|
|
447
|
+
export interface RepoOwner {
|
|
448
|
+
name: string;
|
|
449
|
+
kind: string;
|
|
450
|
+
host?: string | undefined;
|
|
451
|
+
}
|
|
452
|
+
/** One GitLab project, with the server a $host must name to reach it. */
|
|
453
|
+
export interface GitlabProject {
|
|
454
|
+
path: string;
|
|
455
|
+
host: string;
|
|
456
|
+
description: string;
|
|
457
|
+
private: boolean;
|
|
458
|
+
}
|
|
459
|
+
/** One entry in a repository directory listing. */
|
|
460
|
+
export interface RepoEntry {
|
|
461
|
+
path: string;
|
|
462
|
+
type: 'blob' | 'tree';
|
|
409
463
|
}
|
|
410
464
|
import type { FieldComponent } from '../form/fieldRegistry.js';
|
|
411
465
|
import type { PageHeaderCrumb } from './PageHeader.js';
|
|
@@ -431,11 +485,12 @@ export interface UISlots {
|
|
|
431
485
|
* renders fields inside a Suspense boundary.
|
|
432
486
|
*/
|
|
433
487
|
formFields?: Record<string, FieldComponent>;
|
|
434
|
-
/**
|
|
488
|
+
/** Links and sessions block for a run's sidebar; absent hides the section. */
|
|
435
489
|
runSessions?: (args: {
|
|
436
490
|
runId: string;
|
|
437
491
|
runNumber: number;
|
|
438
492
|
runActive: boolean;
|
|
493
|
+
links?: Record<string, RunLink> | undefined;
|
|
439
494
|
}) => ReactNode;
|
|
440
495
|
/** Rich read-only YAML viewer; absent falls back to a plain <pre>. */
|
|
441
496
|
yamlViewer?: (args: {
|
|
@@ -488,9 +543,11 @@ export declare function useNavigation(): UINavigation;
|
|
|
488
543
|
export declare function useSlots(): UISlots;
|
|
489
544
|
export declare function useWorkflowJsonResolver(): ((ref: WorkflowJsonRef) => Promise<unknown>) | undefined;
|
|
490
545
|
export declare function useProvisionCorsRules(): UIData['provisionCorsRules'];
|
|
546
|
+
export declare function useRepoSuggestions(): UIData['repoSuggestions'];
|
|
491
547
|
export declare function useRunFile(slug: string, path: string | null, options?: {
|
|
492
548
|
refreshInterval?: number;
|
|
493
549
|
}): RunFileResult;
|
|
550
|
+
export declare function usePersistedState<T>(key: string, defaultValue: T): [T, Dispatch<SetStateAction<T>>];
|
|
494
551
|
export declare function UIProvider({ notify, strings, navigation, data, slots, children, }: {
|
|
495
552
|
notify?: Partial<UINotify>;
|
|
496
553
|
strings?: {
|
|
@@ -1,6 +1,8 @@
|
|
|
1
1
|
interface ISectionHeaderProps {
|
|
2
2
|
className?: string;
|
|
3
|
+
/** 'sm' heads a group inside a page rather than the page's own section. */
|
|
4
|
+
size?: 'md' | 'sm';
|
|
3
5
|
children: React.ReactNode;
|
|
4
6
|
}
|
|
5
|
-
export default function SectionHeader({ children, className, }: ISectionHeaderProps): import("react").JSX.Element;
|
|
7
|
+
export default function SectionHeader({ children, className, size, }: ISectionHeaderProps): import("react").JSX.Element;
|
|
6
8
|
export {};
|
|
@@ -1,5 +1,5 @@
|
|
|
1
1
|
import type { ReactNode } from 'react';
|
|
2
|
-
type BadgeVariant = 'default' | 'success' | 'warning' | 'error' | 'info' | 'muted';
|
|
2
|
+
export type BadgeVariant = 'default' | 'success' | 'warning' | 'error' | 'info' | 'muted';
|
|
3
3
|
interface StatusBadgeProps {
|
|
4
4
|
/** Badge content */
|
|
5
5
|
children: ReactNode;
|
|
@@ -7,12 +7,17 @@ interface StatusBadgeProps {
|
|
|
7
7
|
variant?: BadgeVariant;
|
|
8
8
|
/** Show animated pulse indicator */
|
|
9
9
|
pulse?: boolean;
|
|
10
|
+
/** Show a still indicator in the variant's colour */
|
|
11
|
+
dot?: boolean;
|
|
10
12
|
/** Size */
|
|
11
13
|
size?: 'sm' | 'md';
|
|
12
14
|
/** Additional class */
|
|
13
15
|
className?: string;
|
|
14
16
|
}
|
|
15
|
-
|
|
17
|
+
/** A line of text in a variant's colour, for a status that stands beside a
|
|
18
|
+
* dot rather than inside a badge. */
|
|
19
|
+
export declare function statusTextClass(variant: BadgeVariant): string;
|
|
20
|
+
export declare function StatusBadge({ children, variant, pulse, dot, size, className, }: StatusBadgeProps): import("react").JSX.Element;
|
|
16
21
|
interface StatusDotProps {
|
|
17
22
|
variant?: BadgeVariant;
|
|
18
23
|
pulse?: boolean;
|
|
@@ -0,0 +1,15 @@
|
|
|
1
|
+
import { DateTime } from 'luxon';
|
|
2
|
+
export declare function compactRelativeMinutes(minutes: number, t: {
|
|
3
|
+
now: string;
|
|
4
|
+
minutes: (n: number) => string;
|
|
5
|
+
hours: (n: number) => string;
|
|
6
|
+
days: (n: number) => string;
|
|
7
|
+
years: (n: number) => string;
|
|
8
|
+
}): string;
|
|
9
|
+
/** A clock that re-reads itself, so "5m" ages while the page sits open, with
|
|
10
|
+
* the abbreviated form a row has room for. */
|
|
11
|
+
export declare function useRelativeTime(): {
|
|
12
|
+
now: DateTime;
|
|
13
|
+
compact: (iso: string | undefined) => string;
|
|
14
|
+
compactMinutes: (minutes: number) => string;
|
|
15
|
+
};
|
package/dist/editor/index.js
CHANGED
|
@@ -1,2 +1,2 @@
|
|
|
1
|
-
import { a as EditorField, i as FormCodePanel, n as defineEditorThemes, o as Editor, r as getThemeName, t as setupMonacoWorkers } from "../chunks/editor-
|
|
1
|
+
import { a as EditorField, i as FormCodePanel, n as defineEditorThemes, o as Editor, r as getThemeName, t as setupMonacoWorkers } from "../chunks/editor-9_uVtUyy.js";
|
|
2
2
|
export { Editor, EditorField, FormCodePanel, defineEditorThemes, getThemeName, setupMonacoWorkers };
|
|
@@ -0,0 +1,97 @@
|
|
|
1
|
+
/** Pure helpers behind the gitlab/ uses: completion, kept out of Monaco.tsx so they can
|
|
2
|
+
* be tested without loading the editor. */
|
|
3
|
+
export interface MonacoRange {
|
|
4
|
+
startLineNumber: number;
|
|
5
|
+
startColumn: number;
|
|
6
|
+
endLineNumber: number;
|
|
7
|
+
endColumn: number;
|
|
8
|
+
}
|
|
9
|
+
interface LineReader {
|
|
10
|
+
getLineContent: (line: number) => string;
|
|
11
|
+
}
|
|
12
|
+
/** Splits GROUP/PROJECT@REF; the ref is null when no @ has been typed yet. */
|
|
13
|
+
export declare function splitAtRef(typed: string): [string, string | null];
|
|
14
|
+
/** What to insert for a chosen project, given what is already typed. A typed prefix is
|
|
15
|
+
* completed like the github one; a mid-path match has to replace what is there. */
|
|
16
|
+
export declare function projectInsert(typed: string, path: string): {
|
|
17
|
+
text: string;
|
|
18
|
+
replace: boolean;
|
|
19
|
+
};
|
|
20
|
+
/** The $host the step pins, or undefined. Quotes and a trailing comment are stripped,
|
|
21
|
+
* so a pinned host is recognised however it was written. */
|
|
22
|
+
export declare function stepHostAbove(model: LineReader, usesLine: number, maxLines?: number): string | undefined;
|
|
23
|
+
/** A YAML scalar as written: quotes removed, a trailing comment dropped. */
|
|
24
|
+
export declare function unquoteScalar(raw: string): string;
|
|
25
|
+
/** A missing $host already means gitlab.com, so naming it adds nothing. */
|
|
26
|
+
export declare const DEFAULT_GITLAB_HOST = "gitlab.com";
|
|
27
|
+
/** How to add `$host` to a step. Always an edit of its own: monaco re-indents a
|
|
28
|
+
* multi-line insertText, and the cursor has to stay after the project. */
|
|
29
|
+
export declare function hostCompletion(model: LineReader & {
|
|
30
|
+
getLineCount: () => number;
|
|
31
|
+
}, usesLine: number, host: string): {
|
|
32
|
+
appendText: string;
|
|
33
|
+
edits: {
|
|
34
|
+
range: MonacoRange;
|
|
35
|
+
text: string;
|
|
36
|
+
}[];
|
|
37
|
+
};
|
|
38
|
+
/** A trailing slash or @ after a known project is the ref separator, the way a trailing
|
|
39
|
+
* slash is for github/OWNER/REPO. The slash is swapped for @ when a ref is accepted. */
|
|
40
|
+
export declare function refTrigger(typed: string, knownPaths: string[]): {
|
|
41
|
+
projectPath: string;
|
|
42
|
+
replaceSlash: boolean;
|
|
43
|
+
} | undefined;
|
|
44
|
+
/** What to ask the platform for when completing a project path: everything before the
|
|
45
|
+
* first slash. Typing deeper then filters that answer instead of asking again. */
|
|
46
|
+
export declare function projectSearchKey(typed: string): string;
|
|
47
|
+
/** Where a `$yaml:`/`$thumbnail:` value's files come from: the nearest `uses:` above,
|
|
48
|
+
* addressed the way the platform's file endpoint expects. A gitlab/ path carries no
|
|
49
|
+
* host, so the step's $host supplies it. */
|
|
50
|
+
export declare function usesFileSource(model: LineReader, fromLine: number, maxLines?: number): {
|
|
51
|
+
repo: string;
|
|
52
|
+
ref: string;
|
|
53
|
+
} | undefined;
|
|
54
|
+
/** One entry of a repository tree. */
|
|
55
|
+
export interface RepoTreeEntry {
|
|
56
|
+
path: string;
|
|
57
|
+
type: 'tree' | 'blob';
|
|
58
|
+
}
|
|
59
|
+
declare const FILE_VALUE_KINDS: {
|
|
60
|
+
$yaml: {
|
|
61
|
+
detail: string;
|
|
62
|
+
keep: (path: string) => boolean;
|
|
63
|
+
};
|
|
64
|
+
$thumbnail: {
|
|
65
|
+
detail: string;
|
|
66
|
+
keep: (path: string) => boolean;
|
|
67
|
+
};
|
|
68
|
+
};
|
|
69
|
+
/** Which of the two file-valued keys the cursor sits on, if either. */
|
|
70
|
+
export declare function fileValueKey(textUntilCursor: string): keyof typeof FILE_VALUE_KINDS | undefined;
|
|
71
|
+
/** The files worth offering for a `$yaml:`/`$thumbnail:` value, from whichever
|
|
72
|
+
* repository the step's `uses:` names. Empty when the line is not one of those keys,
|
|
73
|
+
* no `uses:` is above it, or the tree cannot be read. */
|
|
74
|
+
export declare function fileValueSuggestions(model: LineReader, line: number, textUntilCursor: string, loadTree: (repo: string, ref: string) => Promise<RepoTreeEntry[]>): Promise<{
|
|
75
|
+
path: string;
|
|
76
|
+
detail: string;
|
|
77
|
+
}[]>;
|
|
78
|
+
/** Every $-prefixed key a step already sets, mapped to its value. Nothing already
|
|
79
|
+
* written is offered a second time, and an existing one must not suppress the rest. */
|
|
80
|
+
export declare function specialKeysNearUses(model: LineReader & {
|
|
81
|
+
getLineCount: () => number;
|
|
82
|
+
}, usesLineNumber: number): Map<string, string>;
|
|
83
|
+
/** The same, for a with: block located by its own indentation. */
|
|
84
|
+
export declare function specialKeysInWithBlock(model: LineReader & {
|
|
85
|
+
getLineCount: () => number;
|
|
86
|
+
}, withLineNumber: number): Map<string, string>;
|
|
87
|
+
/** Text to be inserted as a snippet, with the characters monaco's snippet parser would
|
|
88
|
+
* otherwise read as placeholders escaped. */
|
|
89
|
+
export declare function snippetLiteral(text: string): string;
|
|
90
|
+
/** How a completion inserts its text when a `$host` block has to travel with it. The
|
|
91
|
+
* cursor stop is what keeps the caret on the uses: line rather than after the block;
|
|
92
|
+
* without a block there is nothing to escape and it stays a plain insert. */
|
|
93
|
+
export declare function completionInsert(text: string, appendText: string): {
|
|
94
|
+
insertText: string;
|
|
95
|
+
isSnippet: boolean;
|
|
96
|
+
};
|
|
97
|
+
export {};
|