@parallelworks/ui 0.1.0 → 0.3.0
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- package/dist/assets/editor.worker-CuBRIwi-.js +14776 -0
- package/dist/assets/json.worker-8ytS02vz.js +22161 -0
- package/dist/assets/yaml.worker-DJC-VUcv.js +48367 -0
- package/dist/chunks/CodePreviewEditor-CSPRILMp.js +61 -0
- package/dist/chunks/Indicator-hBSIxOPK.js +39 -0
- package/dist/chunks/Loader-DQiZ75fa.js +25 -0
- package/dist/chunks/Markdown-C5Re2ezs.js +101 -0
- package/dist/chunks/MarkdownImpl-Bq4QhrtA.js +33 -0
- package/dist/chunks/Modal-sOUEwebV.js +121 -0
- package/dist/chunks/Monaco-CC4ak1JG.js +717 -0
- package/dist/chunks/Provider-DvVvScTQ.js +391 -0
- package/dist/chunks/StatusBadge-DXp4zkSd.js +46 -0
- package/dist/chunks/SwitchToggle-2uRw8ZeJ.js +725 -0
- package/dist/chunks/SwitchToggleSmall-FcsaYSTs.js +14 -0
- package/dist/chunks/Table-C5z6qWjM.js +91 -0
- package/dist/chunks/Tooltip-WgbiC_nd.js +71 -0
- package/dist/chunks/editor-D55tumuZ.js +372 -0
- package/dist/chunks/lib-DTgL8klR.js +191 -0
- package/dist/chunks/list-7PyDF1tz.js +465 -0
- package/dist/components/CollapsiblePanel.d.ts +27 -0
- package/dist/components/CopyToClipboard.d.ts +17 -0
- package/dist/components/Dropdown.d.ts +24 -0
- package/dist/components/Indicator.d.ts +4 -0
- package/dist/components/Listbox.d.ts +18 -0
- package/dist/components/Markdown.d.ts +7 -0
- package/dist/components/MarkdownImpl.d.ts +2 -0
- package/dist/components/MultiSelect.d.ts +19 -0
- package/dist/components/Overview.d.ts +12 -0
- package/dist/components/Provider.d.ts +438 -0
- package/dist/components/SectionHeader.d.ts +6 -0
- package/dist/components/SwitchToggle.d.ts +12 -0
- package/dist/components/SwitchToggleSmall.d.ts +6 -0
- package/dist/components/dropdownUtils.d.ts +18 -0
- package/dist/editor/Editor.d.ts +2 -0
- package/dist/editor/EditorField.d.ts +11 -0
- package/dist/editor/FormCodePanel.d.ts +8 -0
- package/dist/editor/Monaco.d.ts +31 -0
- package/dist/editor/index.d.ts +7 -0
- package/dist/editor/index.js +2 -0
- package/dist/editor/themes.d.ts +4 -0
- package/dist/editor/useCssIsDark.d.ts +6 -0
- package/dist/editor/workers.d.ts +6 -0
- package/dist/file-explorer/FileExplorer.d.ts +23 -0
- package/dist/file-explorer/FileExplorerContext.d.ts +17 -0
- package/dist/file-explorer/FilePreview/CodePreviewEditor.d.ts +6 -0
- package/dist/file-explorer/FilePreview/Inline.d.ts +13 -0
- package/dist/file-explorer/FilePreview/StreamedBadge.d.ts +1 -0
- package/dist/file-explorer/FilePreview/Viewer.d.ts +15 -0
- package/dist/file-explorer/FilePreview/index.d.ts +15 -0
- package/dist/file-explorer/FilePreview/parse.d.ts +24 -0
- package/dist/file-explorer/FilePreview/previewCache.d.ts +26 -0
- package/dist/file-explorer/FilePreview/previewType.d.ts +21 -0
- package/dist/file-explorer/FilePreview/readCappedBytes.d.ts +37 -0
- package/dist/file-explorer/FilePreview/useObjectBlobUrl.d.ts +16 -0
- package/dist/file-explorer/FilePreview/useObjectText.d.ts +23 -0
- package/dist/file-explorer/FilePreview/usePresignedUrl.d.ts +12 -0
- package/dist/file-explorer/FileRow.d.ts +35 -0
- package/dist/file-explorer/FileRowsWindow.d.ts +43 -0
- package/dist/file-explorer/FileTable.d.ts +26 -0
- package/dist/file-explorer/FileTableHeaders.d.ts +13 -0
- package/dist/file-explorer/LoadMoreRow.d.ts +15 -0
- package/dist/file-explorer/TreeView.d.ts +28 -0
- package/dist/file-explorer/helpers.d.ts +47 -0
- package/dist/file-explorer/index.d.ts +10 -0
- package/dist/file-explorer/index.js +5646 -0
- package/dist/file-explorer/lib/batch.d.ts +3 -0
- package/dist/file-explorer/lib/errors.d.ts +3 -0
- package/dist/file-explorer/lib/fileExplorer.d.ts +32 -0
- package/dist/file-explorer/lib/paging.d.ts +93 -0
- package/dist/file-explorer/lib/types.d.ts +92 -0
- package/dist/file-explorer/lib/utils.d.ts +37 -0
- package/dist/file-explorer/toasts.d.ts +9 -0
- package/dist/file-explorer/treeRows.d.ts +35 -0
- package/dist/file-explorer/useNearEnd.d.ts +7 -0
- package/dist/form/FieldWrapper.d.ts +10 -0
- package/dist/form/Fields/BooleanField.d.ts +12 -0
- package/dist/form/Fields/BucketReadOnlyField.d.ts +7 -0
- package/dist/form/Fields/CheckboxGroupField.d.ts +18 -0
- package/dist/form/Fields/ColorField.d.ts +8 -0
- package/dist/form/Fields/DropdownField.d.ts +24 -0
- package/dist/form/Fields/DurationField.d.ts +13 -0
- package/dist/form/Fields/LabelField.d.ts +9 -0
- package/dist/form/Fields/MultiDropdownField.d.ts +18 -0
- package/dist/form/Fields/NumberField.d.ts +13 -0
- package/dist/form/Fields/ObjectField.d.ts +8 -0
- package/dist/form/Fields/RadioField.d.ts +9 -0
- package/dist/form/Fields/RangeField.d.ts +11 -0
- package/dist/form/Fields/ResourceOptionIcon.d.ts +11 -0
- package/dist/form/Fields/StepField.d.ts +3 -0
- package/dist/form/Fields/StringField.d.ts +17 -0
- package/dist/form/Fields/TextAreaField.d.ts +8 -0
- package/dist/form/Fields/durationValidity.d.ts +2 -0
- package/dist/form/Form.d.ts +105 -0
- package/dist/form/SpecialTypes/DropdownWrapper.d.ts +14 -0
- package/dist/form/SpecialTypes/FormikCustomDropdown.d.ts +53 -0
- package/dist/form/SpecialTypes/FormikCustomInput.d.ts +17 -0
- package/dist/form/SpecialTypes/FormikMultiSelectDropdown.d.ts +13 -0
- package/dist/form/SpecialTypes/FormikNumericInput.d.ts +9 -0
- package/dist/form/SpecialTypes/index.d.ts +3 -0
- package/dist/form/Wizard/WizardContainer.d.ts +5 -0
- package/dist/form/Wizard/WizardNavigation.d.ts +2 -0
- package/dist/form/Wizard/WizardStepContent.d.ts +8 -0
- package/dist/form/Wizard/WizardStepIndicator.d.ts +2 -0
- package/dist/form/Wizard/types.d.ts +171 -0
- package/dist/form/Wizard/useWizardState.d.ts +28 -0
- package/dist/form/Wizard/utils.d.ts +2 -0
- package/dist/form/fieldRegistry.d.ts +7 -0
- package/dist/form/index.d.ts +16 -0
- package/dist/form/index.js +2319 -0
- package/dist/form/lib.d.ts +15 -0
- package/dist/form/types/fieldComponentTypes.d.ts +32 -0
- package/dist/form/types/fieldTypes.d.ts +80 -0
- package/dist/form/types/workflow-schema.d.ts +1107 -0
- package/dist/form/useParsedOpts.d.ts +5 -0
- package/dist/form/usePrevious.d.ts +1 -0
- package/dist/form/utils/checkShowIfObject.d.ts +1 -0
- package/dist/form/utils/getParentValue.d.ts +1 -0
- package/dist/form/utils/getPlaceholder.d.ts +2 -0
- package/dist/form/utils/getValueUsingPath.d.ts +1 -0
- package/dist/form/utils/pwResolver.d.ts +18 -0
- package/dist/form/utils/secondaryField.d.ts +8 -0
- package/dist/form/utils/slurmDuration.d.ts +15 -0
- package/dist/icons.d.ts +1 -1
- package/dist/icons.js +2 -2
- package/dist/index.d.ts +17 -0
- package/dist/index.js +42 -350
- package/dist/list/ListTable.d.ts +63 -0
- package/dist/list/RowContextMenu.d.ts +113 -0
- package/dist/list/index.d.ts +2 -0
- package/dist/list/index.js +2 -0
- package/dist/logviewer/LogViewer.d.ts +18 -0
- package/dist/logviewer/index.d.ts +1 -0
- package/dist/logviewer/index.js +534 -0
- package/dist/logviewer/logviewer.css +70 -0
- package/dist/styles/theme.css +30 -0
- package/dist/styles.css +1 -1
- package/dist/workflow/AnnotationBanner.d.ts +5 -0
- package/dist/workflow/Collapse.d.ts +6 -0
- package/dist/workflow/DependencyGraph.d.ts +15 -0
- package/dist/workflow/JobSummary.d.ts +38 -0
- package/dist/workflow/MatrixGroup.d.ts +41 -0
- package/dist/workflow/Reveal.d.ts +7 -0
- package/dist/workflow/TreeView.d.ts +42 -0
- package/dist/workflow/index.d.ts +1 -0
- package/dist/workflow/index.js +2331 -0
- package/package.json +71 -6
|
@@ -0,0 +1,191 @@
|
|
|
1
|
+
import cx from "classnames";
|
|
2
|
+
import { jsx, jsxs } from "react/jsx-runtime";
|
|
3
|
+
//#region src/form/FieldWrapper.tsx
|
|
4
|
+
function FieldWrapper({ label, tooltipComponent, description, labelPosition = "left", spaceCompact = false, optional = false, children }) {
|
|
5
|
+
return /* @__PURE__ */ jsxs("div", {
|
|
6
|
+
className: cx("flex w-full", labelPosition === "left" ? "items-start" : "items-left flex-col"),
|
|
7
|
+
children: [/* @__PURE__ */ jsxs("div", {
|
|
8
|
+
className: cx("relative", labelPosition === "left" ? "form-label" : "form-label-top", spaceCompact && "form-label-compact"),
|
|
9
|
+
children: [
|
|
10
|
+
label,
|
|
11
|
+
!optional && /* @__PURE__ */ jsx("span", { children: "*" }),
|
|
12
|
+
tooltipComponent
|
|
13
|
+
]
|
|
14
|
+
}), /* @__PURE__ */ jsxs("div", {
|
|
15
|
+
className: "w-full",
|
|
16
|
+
children: [children, description && /* @__PURE__ */ jsx("div", {
|
|
17
|
+
className: "text-xs theme-muted-text mt-1 leading-relaxed",
|
|
18
|
+
children: description
|
|
19
|
+
})]
|
|
20
|
+
})]
|
|
21
|
+
});
|
|
22
|
+
}
|
|
23
|
+
//#endregion
|
|
24
|
+
//#region src/form/utils/secondaryField.ts
|
|
25
|
+
function findSecondaryOption(options, value) {
|
|
26
|
+
for (const candidate of options) {
|
|
27
|
+
if (!candidate || typeof candidate !== "object") continue;
|
|
28
|
+
const option = candidate;
|
|
29
|
+
if (option.value === value) return option;
|
|
30
|
+
if (Array.isArray(option.options)) {
|
|
31
|
+
const nestedOption = findSecondaryOption(option.options, value);
|
|
32
|
+
if (nestedOption) return nestedOption;
|
|
33
|
+
}
|
|
34
|
+
}
|
|
35
|
+
}
|
|
36
|
+
function applySecondaryField(secondaryField, secondaryValue, setFieldValue) {
|
|
37
|
+
if (secondaryField === void 0 || secondaryValue === void 0) return;
|
|
38
|
+
const fields = Array.isArray(secondaryField) ? secondaryField : [secondaryField];
|
|
39
|
+
const values = Array.isArray(secondaryValue) ? secondaryValue : [secondaryValue];
|
|
40
|
+
fields.forEach((field, index) => {
|
|
41
|
+
setFieldValue(field, values[index]);
|
|
42
|
+
});
|
|
43
|
+
}
|
|
44
|
+
//#endregion
|
|
45
|
+
//#region src/form/lib.ts
|
|
46
|
+
/**
|
|
47
|
+
* Drops a schema flag the expression parser could not resolve. workflow.schema.json types
|
|
48
|
+
* `optional`/`hidden`/`ignore` as ["string", "boolean"], so a flag whose expression depends
|
|
49
|
+
* on something unavailable at form-render time (a list `[index]` outside a row, `needs.`,
|
|
50
|
+
* `env.`, a secret `var.`) arrives as the raw `${{…}}` string. That string is truthy, which
|
|
51
|
+
* inverts each flag's documented `false` default. Returning undefined lets the caller apply
|
|
52
|
+
* that default instead of reading an expression it never evaluated as "yes".
|
|
53
|
+
*/
|
|
54
|
+
function resolvedFlag(value) {
|
|
55
|
+
return typeof value === "string" && value.includes("${{") ? void 0 : value;
|
|
56
|
+
}
|
|
57
|
+
function enforceOneMustBeTrue(items, options, promoteIndex) {
|
|
58
|
+
if (items.length === 0) return items;
|
|
59
|
+
const clampedIndex = Math.max(0, Math.min(promoteIndex, items.length - 1));
|
|
60
|
+
const oneMustBeTrueFields = Object.keys(options).filter((key) => typeof options[key] === "object" && options[key] !== null && "one_must_be_true" in options[key] && options[key].one_must_be_true);
|
|
61
|
+
for (const fieldKey of oneMustBeTrueFields) {
|
|
62
|
+
const fieldSchema = options[fieldKey];
|
|
63
|
+
if (typeof fieldSchema === "object" && fieldSchema && "options" in fieldSchema) {
|
|
64
|
+
const opts = fieldSchema.options;
|
|
65
|
+
const trueOption = typeof opts === "object" && opts && !Array.isArray(opts) && "onOption" in opts ? opts.onOption || true : true;
|
|
66
|
+
if (!items.some((item) => item[fieldKey] === trueOption)) items[clampedIndex][fieldKey] = trueOption;
|
|
67
|
+
}
|
|
68
|
+
}
|
|
69
|
+
return items;
|
|
70
|
+
}
|
|
71
|
+
function flattenGroups(schema) {
|
|
72
|
+
if (!schema) return {};
|
|
73
|
+
let flattenedFields = {};
|
|
74
|
+
Object.keys(schema).forEach((key) => {
|
|
75
|
+
if (schema[key].type === "group") {
|
|
76
|
+
const flattenedGroup = flattenGroups(schema[key].options);
|
|
77
|
+
flattenedFields = {
|
|
78
|
+
...flattenedFields,
|
|
79
|
+
...flattenedGroup
|
|
80
|
+
};
|
|
81
|
+
} else if (schema[key].type === "object") {
|
|
82
|
+
const flattenedGroup = flattenGroups(schema[key].options);
|
|
83
|
+
flattenedFields = {
|
|
84
|
+
...flattenedFields,
|
|
85
|
+
[key]: flattenedGroup
|
|
86
|
+
};
|
|
87
|
+
} else flattenedFields[key] = schema[key];
|
|
88
|
+
});
|
|
89
|
+
return flattenedFields;
|
|
90
|
+
}
|
|
91
|
+
/**Not a pure function. Edits 'obj' passed into function */
|
|
92
|
+
function impureSetValueFromPath(obj, path, value) {
|
|
93
|
+
const pathArray = path.split(".");
|
|
94
|
+
if (pathArray.length === 1) {
|
|
95
|
+
obj[pathArray[0]] = value;
|
|
96
|
+
return;
|
|
97
|
+
}
|
|
98
|
+
let current = obj;
|
|
99
|
+
for (let i = 0; i < pathArray.length - 1; i++) {
|
|
100
|
+
const segment = pathArray[i];
|
|
101
|
+
const arrayMatch = segment.match(/^(.+)\[(\d+)\]$/);
|
|
102
|
+
if (arrayMatch) {
|
|
103
|
+
const key = arrayMatch[1];
|
|
104
|
+
const index = Number(arrayMatch[2]);
|
|
105
|
+
if (!current[key]) current[key] = [];
|
|
106
|
+
if (!current[key][index]) current[key][index] = {};
|
|
107
|
+
current = current[key][index];
|
|
108
|
+
} else {
|
|
109
|
+
if (!current[segment]) current[segment] = {};
|
|
110
|
+
current = current[segment];
|
|
111
|
+
}
|
|
112
|
+
}
|
|
113
|
+
current[pathArray[pathArray.length - 1]] = value;
|
|
114
|
+
}
|
|
115
|
+
function initializeValues(options, srcData = {}, ignoreDefaultStrings = false) {
|
|
116
|
+
if (!options) return;
|
|
117
|
+
const data = structuredClone(srcData);
|
|
118
|
+
return Object.keys(options).reduce((acc, field) => {
|
|
119
|
+
if (field.startsWith("$")) return acc;
|
|
120
|
+
if (options[field].type === "group") {
|
|
121
|
+
const values = initializeValues(options[field].options, data);
|
|
122
|
+
if (!values) return acc;
|
|
123
|
+
Object.keys(values).forEach((key) => {
|
|
124
|
+
acc[key] = data[key] ?? values[key];
|
|
125
|
+
});
|
|
126
|
+
return acc;
|
|
127
|
+
}
|
|
128
|
+
if (options[field].type === "step") {
|
|
129
|
+
if (options.$meta?.wizard?.flatten !== false) {
|
|
130
|
+
const values = initializeValues(options[field].options, data);
|
|
131
|
+
if (!values) return acc;
|
|
132
|
+
Object.keys(values).forEach((key) => {
|
|
133
|
+
acc[key] = data[key] ?? values[key];
|
|
134
|
+
});
|
|
135
|
+
} else acc[field] = initializeValues(options[field].options, data[field] || {});
|
|
136
|
+
return acc;
|
|
137
|
+
}
|
|
138
|
+
if (options[field].type === "object") {
|
|
139
|
+
acc[field] = initializeValues(options[field].options, data[field] || {});
|
|
140
|
+
return acc;
|
|
141
|
+
}
|
|
142
|
+
if (options[field].type === "list") {
|
|
143
|
+
if (options[field].options === "string") {
|
|
144
|
+
acc[field] = Array.isArray(data[field]) ? [...data[field]] : [];
|
|
145
|
+
return acc;
|
|
146
|
+
}
|
|
147
|
+
const arr = [];
|
|
148
|
+
if (data[field]) for (let i = 0; i < data[field].length; i++) arr.push(initializeValues(options[field].options, data[field][i] || {}));
|
|
149
|
+
acc[field] = arr;
|
|
150
|
+
return acc;
|
|
151
|
+
}
|
|
152
|
+
if (data[field] !== void 0) {
|
|
153
|
+
acc[field] = data[field];
|
|
154
|
+
if ((options[field].type === "dropdown" || options[field].type === "storage") && options[field].secondaryField && options[field].options && Array.isArray(options[field].options)) {
|
|
155
|
+
const option = findSecondaryOption(options[field].options, data[field]);
|
|
156
|
+
applySecondaryField(options[field].secondaryField, option?.secondaryValue, (secondaryField, secondaryValue) => {
|
|
157
|
+
if (!(options[field].type === "storage" && Object.prototype.hasOwnProperty.call(options, secondaryField) && srcData[secondaryField] !== void 0)) impureSetValueFromPath(acc, secondaryField, secondaryValue);
|
|
158
|
+
});
|
|
159
|
+
}
|
|
160
|
+
return acc;
|
|
161
|
+
}
|
|
162
|
+
if (options[field].type === "label") return acc;
|
|
163
|
+
if (options[field].optional && options[field].default === void 0) return acc;
|
|
164
|
+
acc[field] = "";
|
|
165
|
+
if (options[field].autoselect) acc[field] = void 0;
|
|
166
|
+
if (options[field].type === "boolean") if (options[field].options?.offOption && options[field].options?.onOption) acc[field] = options[field].options.offOption;
|
|
167
|
+
else acc[field] = false;
|
|
168
|
+
if (options[field].type === "dropdown") {
|
|
169
|
+
if (options[field].options && Array.isArray(options[field].options) && options[field].options.length > 0) acc[field] = options[field].options[0].value;
|
|
170
|
+
if (options[field].type === "dropdown" && options[field].secondaryField && options[field].options && Array.isArray(options[field].options)) {
|
|
171
|
+
const option = options[field].options.find((option) => option.value === data[field]);
|
|
172
|
+
const secondaryField = Array.isArray(options[field].secondaryField) ? options[field].secondaryField : [options[field].secondaryField];
|
|
173
|
+
const secondaryValue = Array.isArray(option?.secondaryValue) ? option?.secondaryValue : [option?.secondaryValue];
|
|
174
|
+
secondaryField.forEach((field, index) => {
|
|
175
|
+
impureSetValueFromPath(data, field, secondaryValue[index]);
|
|
176
|
+
impureSetValueFromPath(acc, field, secondaryValue[index]);
|
|
177
|
+
});
|
|
178
|
+
}
|
|
179
|
+
}
|
|
180
|
+
if (options[field].type === "multi-dropdown" || options[field].type === "checkbox-group") acc[field] = [];
|
|
181
|
+
if (options[field].default !== void 0) {
|
|
182
|
+
const dflt = options[field].default;
|
|
183
|
+
const isPwResource = typeof dflt === "string" && dflt.startsWith("pw://");
|
|
184
|
+
acc[field] = options[field].type === "string" || ignoreDefaultStrings && !isPwResource && (options[field].type === "textarea" || options[field].type === "compute-clusters" || options[field].type === "compute-resources") ? "" : dflt;
|
|
185
|
+
}
|
|
186
|
+
if (options[field].prefillDefault && options[field].default !== void 0) acc[field] = options[field].default;
|
|
187
|
+
return acc;
|
|
188
|
+
}, data);
|
|
189
|
+
}
|
|
190
|
+
//#endregion
|
|
191
|
+
export { resolvedFlag as a, FieldWrapper as c, initializeValues as i, flattenGroups as n, applySecondaryField as o, impureSetValueFromPath as r, findSecondaryOption as s, enforceOneMustBeTrue as t };
|
|
@@ -0,0 +1,465 @@
|
|
|
1
|
+
import { CheckIcon, ChevronRightIcon, ClipboardIcon, CopyIcon, ErrorIcon, IdCardIcon, KeyIcon, LinkIcon, MailIcon, MoreIcon, UserIcon } from "../icons.js";
|
|
2
|
+
import { c as useStrings, i as useNotify, n as useLink } from "./Provider-DvVvScTQ.js";
|
|
3
|
+
import { n as Table } from "./Table-C5z6qWjM.js";
|
|
4
|
+
import cx from "classnames";
|
|
5
|
+
import { Fragment, jsx, jsxs } from "react/jsx-runtime";
|
|
6
|
+
import { useCallback, useEffect, useLayoutEffect, useRef, useState } from "react";
|
|
7
|
+
import { createPortal } from "react-dom";
|
|
8
|
+
//#region src/list/RowContextMenu.tsx
|
|
9
|
+
/** Converts a single row action to a menu item: a `to` makes it a link, otherwise an action. */
|
|
10
|
+
function toRowMenuItem(action) {
|
|
11
|
+
if (action.to) return {
|
|
12
|
+
kind: "link",
|
|
13
|
+
label: action.label,
|
|
14
|
+
icon: action.icon,
|
|
15
|
+
to: action.to,
|
|
16
|
+
destructive: action.destructive
|
|
17
|
+
};
|
|
18
|
+
return {
|
|
19
|
+
kind: "action",
|
|
20
|
+
label: action.label,
|
|
21
|
+
icon: action.icon,
|
|
22
|
+
onSelect: action.onSelect ?? (() => {}),
|
|
23
|
+
disabled: action.disabled,
|
|
24
|
+
destructive: action.destructive
|
|
25
|
+
};
|
|
26
|
+
}
|
|
27
|
+
/** Bridges a toolbar action (icon component, `onClick`/`href`) onto the shared
|
|
28
|
+
* `RowAction` shape. Typed structurally so any toolbar action shape matching
|
|
29
|
+
* these fields is assignable. */
|
|
30
|
+
function toolbarActionToRowAction(action) {
|
|
31
|
+
const Icon = action.icon;
|
|
32
|
+
return {
|
|
33
|
+
key: action.key,
|
|
34
|
+
label: action.label,
|
|
35
|
+
icon: /* @__PURE__ */ jsx(Icon, {}),
|
|
36
|
+
onSelect: action.onClick,
|
|
37
|
+
to: action.href,
|
|
38
|
+
disabled: action.disabled,
|
|
39
|
+
destructive: action.key === "delete" || action.key === "destroy"
|
|
40
|
+
};
|
|
41
|
+
}
|
|
42
|
+
/** Assembles a row's context menu in the shared order: leading link(s) → middle
|
|
43
|
+
* actions → extra items → Copy submenu → trailing (destructive) actions last. */
|
|
44
|
+
function assembleRowMenu({ lead = [], actions, exclude, order, trailing = ["delete"], extra = [], copy }) {
|
|
45
|
+
const trailingSet = new Set(trailing);
|
|
46
|
+
const excludeSet = new Set(exclude);
|
|
47
|
+
let middle = actions.filter((a) => !trailingSet.has(a.key) && !excludeSet.has(a.key));
|
|
48
|
+
if (order) {
|
|
49
|
+
const byKey = new Map(middle.map((a) => [a.key, a]));
|
|
50
|
+
middle = order.map((key) => byKey.get(key)).filter((a) => a !== void 0);
|
|
51
|
+
}
|
|
52
|
+
const trailingItems = trailing.map((key) => actions.find((a) => a.key === key)).filter((a) => a !== void 0);
|
|
53
|
+
return [
|
|
54
|
+
...lead,
|
|
55
|
+
...middle.map(toRowMenuItem),
|
|
56
|
+
...extra,
|
|
57
|
+
...copy ? [copy] : [],
|
|
58
|
+
...trailingItems.map(toRowMenuItem)
|
|
59
|
+
];
|
|
60
|
+
}
|
|
61
|
+
function useRowMenu() {
|
|
62
|
+
const [menu, setMenu] = useState(null);
|
|
63
|
+
const onCloseRef = useRef(void 0);
|
|
64
|
+
return {
|
|
65
|
+
openMenu: useCallback((x, y, items, onClose) => {
|
|
66
|
+
if (items.length > 0) {
|
|
67
|
+
onCloseRef.current?.();
|
|
68
|
+
onCloseRef.current = onClose;
|
|
69
|
+
setMenu({
|
|
70
|
+
x,
|
|
71
|
+
y,
|
|
72
|
+
items
|
|
73
|
+
});
|
|
74
|
+
}
|
|
75
|
+
}, []),
|
|
76
|
+
contextMenu: /* @__PURE__ */ jsx(RowContextMenu, {
|
|
77
|
+
state: menu,
|
|
78
|
+
onClose: useCallback(() => {
|
|
79
|
+
onCloseRef.current?.();
|
|
80
|
+
onCloseRef.current = void 0;
|
|
81
|
+
setMenu(null);
|
|
82
|
+
}, [])
|
|
83
|
+
})
|
|
84
|
+
};
|
|
85
|
+
}
|
|
86
|
+
/** The full-screen menu overlay drops CSS :hover on the triggering row; wrap openMenu here to substitute a JS-driven `active` highlight. */
|
|
87
|
+
function useRowMenuActive(openMenu) {
|
|
88
|
+
const [active, setActive] = useState(false);
|
|
89
|
+
return {
|
|
90
|
+
active,
|
|
91
|
+
openMenu: useCallback((x, y, items) => {
|
|
92
|
+
setActive(true);
|
|
93
|
+
openMenu(x, y, items, () => setActive(false));
|
|
94
|
+
}, [openMenu])
|
|
95
|
+
};
|
|
96
|
+
}
|
|
97
|
+
function rowContextMenuProps(openMenu, items) {
|
|
98
|
+
return { onContextMenu: (e) => {
|
|
99
|
+
e.preventDefault();
|
|
100
|
+
if (items.length > 0) e.stopPropagation();
|
|
101
|
+
openMenu(e.clientX, e.clientY, items);
|
|
102
|
+
} };
|
|
103
|
+
}
|
|
104
|
+
function RowContextMenu({ state, onClose }) {
|
|
105
|
+
const ref = useRef(null);
|
|
106
|
+
const [pos, setPos] = useState(null);
|
|
107
|
+
useLayoutEffect(() => {
|
|
108
|
+
if (!state || !ref.current) {
|
|
109
|
+
setPos(null);
|
|
110
|
+
return;
|
|
111
|
+
}
|
|
112
|
+
const { width, height } = ref.current.getBoundingClientRect();
|
|
113
|
+
const pad = 8;
|
|
114
|
+
const top = height > window.innerHeight - pad - state.y && state.y - height - pad >= 0 ? state.y - height : Math.min(state.y, window.innerHeight - height - pad);
|
|
115
|
+
setPos({
|
|
116
|
+
left: Math.max(pad, Math.min(state.x, window.innerWidth - width - pad)),
|
|
117
|
+
top: Math.max(pad, top)
|
|
118
|
+
});
|
|
119
|
+
}, [state]);
|
|
120
|
+
useEffect(() => {
|
|
121
|
+
if (!state) return;
|
|
122
|
+
const close = () => onClose();
|
|
123
|
+
const onKey = (e) => {
|
|
124
|
+
if (e.key === "Escape") onClose();
|
|
125
|
+
};
|
|
126
|
+
window.addEventListener("scroll", close, true);
|
|
127
|
+
window.addEventListener("resize", close);
|
|
128
|
+
window.addEventListener("keydown", onKey);
|
|
129
|
+
return () => {
|
|
130
|
+
window.removeEventListener("scroll", close, true);
|
|
131
|
+
window.removeEventListener("resize", close);
|
|
132
|
+
window.removeEventListener("keydown", onKey);
|
|
133
|
+
};
|
|
134
|
+
}, [state, onClose]);
|
|
135
|
+
if (!state) return null;
|
|
136
|
+
const side = (pos?.left ?? state.x) > window.innerWidth * .6 ? "left" : "right";
|
|
137
|
+
return createPortal(/* @__PURE__ */ jsx("div", {
|
|
138
|
+
className: "fixed inset-0 z-50",
|
|
139
|
+
onClick: onClose,
|
|
140
|
+
onContextMenu: (e) => {
|
|
141
|
+
e.preventDefault();
|
|
142
|
+
if (ref.current?.contains(e.target)) {
|
|
143
|
+
onClose();
|
|
144
|
+
return;
|
|
145
|
+
}
|
|
146
|
+
const { clientX, clientY } = e;
|
|
147
|
+
const overlay = e.currentTarget;
|
|
148
|
+
overlay.style.pointerEvents = "none";
|
|
149
|
+
const under = document.elementFromPoint(clientX, clientY);
|
|
150
|
+
overlay.style.pointerEvents = "";
|
|
151
|
+
onClose();
|
|
152
|
+
under?.dispatchEvent(new MouseEvent("contextmenu", {
|
|
153
|
+
bubbles: true,
|
|
154
|
+
cancelable: true,
|
|
155
|
+
clientX,
|
|
156
|
+
clientY
|
|
157
|
+
}));
|
|
158
|
+
},
|
|
159
|
+
children: /* @__PURE__ */ jsx("div", {
|
|
160
|
+
ref,
|
|
161
|
+
role: "menu",
|
|
162
|
+
className: "absolute min-w-44 rounded-lg border border-(--theme-border) bg-(--theme-panel-bg) py-1 shadow-lg backdrop-blur-xl",
|
|
163
|
+
style: {
|
|
164
|
+
left: pos?.left ?? state.x,
|
|
165
|
+
top: pos?.top ?? state.y,
|
|
166
|
+
visibility: pos ? "visible" : "hidden"
|
|
167
|
+
},
|
|
168
|
+
onClick: (e) => e.stopPropagation(),
|
|
169
|
+
children: /* @__PURE__ */ jsx(MenuItemList, {
|
|
170
|
+
items: state.items,
|
|
171
|
+
onClose,
|
|
172
|
+
side
|
|
173
|
+
})
|
|
174
|
+
})
|
|
175
|
+
}), document.body);
|
|
176
|
+
}
|
|
177
|
+
var MENU_ITEM_CLASSES = "flex w-full items-center gap-2.5 px-3 py-1.5 text-left text-[13px] hover:bg-(--theme-muted-panel-bg) transition-colors cursor-pointer [&>svg]:h-4 [&>svg]:w-4 [&>svg]:shrink-0";
|
|
178
|
+
function MenuItemList({ items, onClose, side }) {
|
|
179
|
+
return items.map((item, i) => item.kind === "divider" ? /* @__PURE__ */ jsx("div", {
|
|
180
|
+
"aria-hidden": "true",
|
|
181
|
+
className: "my-1 h-px bg-(--theme-border)"
|
|
182
|
+
}, `divider-${i}`) : /* @__PURE__ */ jsx(MenuRow, {
|
|
183
|
+
item,
|
|
184
|
+
onClose,
|
|
185
|
+
side
|
|
186
|
+
}, `${item.label}-${i}`));
|
|
187
|
+
}
|
|
188
|
+
function MenuRow({ item, onClose, side }) {
|
|
189
|
+
const Link = useLink();
|
|
190
|
+
const notify = useNotify();
|
|
191
|
+
const { list: t } = useStrings();
|
|
192
|
+
const [openSub, setOpenSub] = useState(false);
|
|
193
|
+
const closeTimer = useRef(void 0);
|
|
194
|
+
if (item.kind === "submenu") {
|
|
195
|
+
const open = () => {
|
|
196
|
+
clearTimeout(closeTimer.current);
|
|
197
|
+
setOpenSub(true);
|
|
198
|
+
};
|
|
199
|
+
const close = () => {
|
|
200
|
+
closeTimer.current = setTimeout(() => setOpenSub(false), 160);
|
|
201
|
+
};
|
|
202
|
+
return /* @__PURE__ */ jsxs("div", {
|
|
203
|
+
className: "relative",
|
|
204
|
+
onMouseEnter: open,
|
|
205
|
+
onMouseLeave: close,
|
|
206
|
+
children: [/* @__PURE__ */ jsxs("div", {
|
|
207
|
+
className: cx(MENU_ITEM_CLASSES, "justify-between text-(--theme-app)"),
|
|
208
|
+
children: [/* @__PURE__ */ jsxs("span", {
|
|
209
|
+
className: "flex items-center gap-2.5",
|
|
210
|
+
children: [item.icon, item.label]
|
|
211
|
+
}), /* @__PURE__ */ jsx(ChevronRightIcon, { className: "h-3 w-3 shrink-0 opacity-60" })]
|
|
212
|
+
}), openSub && /* @__PURE__ */ jsx("div", {
|
|
213
|
+
className: cx("absolute -top-1 z-10 min-w-44 rounded-lg border border-(--theme-border) bg-(--theme-panel-bg) py-1 shadow-lg", side === "left" ? "right-full" : "left-full"),
|
|
214
|
+
children: /* @__PURE__ */ jsx(MenuItemList, {
|
|
215
|
+
items: item.items,
|
|
216
|
+
onClose,
|
|
217
|
+
side
|
|
218
|
+
})
|
|
219
|
+
})]
|
|
220
|
+
});
|
|
221
|
+
}
|
|
222
|
+
if (item.kind === "link") return /* @__PURE__ */ jsxs(Link, {
|
|
223
|
+
to: item.to,
|
|
224
|
+
onClick: onClose,
|
|
225
|
+
className: cx(MENU_ITEM_CLASSES, item.destructive ? "text-red-500" : "text-(--theme-app)"),
|
|
226
|
+
children: [item.icon, item.label]
|
|
227
|
+
});
|
|
228
|
+
return /* @__PURE__ */ jsxs("button", {
|
|
229
|
+
type: "button",
|
|
230
|
+
disabled: item.disabled,
|
|
231
|
+
onClick: () => {
|
|
232
|
+
if (item.copy) {
|
|
233
|
+
const { text, label } = item.copy;
|
|
234
|
+
navigator.clipboard?.writeText(text).then(() => notify.success(t.copied(label)), () => notify.error(t.couldntCopy(label)));
|
|
235
|
+
}
|
|
236
|
+
item.onSelect?.();
|
|
237
|
+
onClose();
|
|
238
|
+
},
|
|
239
|
+
className: cx(MENU_ITEM_CLASSES, item.destructive ? "text-red-500" : "text-(--theme-app)", item.disabled && "opacity-40 cursor-not-allowed hover:bg-transparent"),
|
|
240
|
+
children: [
|
|
241
|
+
item.icon,
|
|
242
|
+
item.label,
|
|
243
|
+
item.selected && /* @__PURE__ */ jsx(CheckIcon, { className: "ml-auto opacity-80" })
|
|
244
|
+
]
|
|
245
|
+
});
|
|
246
|
+
}
|
|
247
|
+
/** Builds the Copy submenu entries for whichever fields a row has, in stable
|
|
248
|
+
* order. The menu itself performs the copy and notifies; `t` is an optional
|
|
249
|
+
* host translator for the field labels (falls back to the provider defaults'
|
|
250
|
+
* English). */
|
|
251
|
+
function copySubmenu({ name, nameLabel, email, username, uid, id, url, extra, t }) {
|
|
252
|
+
const items = [
|
|
253
|
+
{
|
|
254
|
+
label: nameLabel ?? (t ? t("rowContextMenu.labelName") : "name"),
|
|
255
|
+
value: name,
|
|
256
|
+
icon: /* @__PURE__ */ jsx(CopyIcon, {})
|
|
257
|
+
},
|
|
258
|
+
{
|
|
259
|
+
label: t ? t("rowContextMenu.labelEmail") : "email",
|
|
260
|
+
value: email,
|
|
261
|
+
icon: /* @__PURE__ */ jsx(MailIcon, {})
|
|
262
|
+
},
|
|
263
|
+
{
|
|
264
|
+
label: t ? t("rowContextMenu.labelUsername") : "username",
|
|
265
|
+
value: username,
|
|
266
|
+
icon: /* @__PURE__ */ jsx(UserIcon, {})
|
|
267
|
+
},
|
|
268
|
+
{
|
|
269
|
+
label: t ? t("rowContextMenu.labelUid") : "UID",
|
|
270
|
+
value: uid === null || uid === void 0 ? null : String(uid),
|
|
271
|
+
icon: /* @__PURE__ */ jsx(KeyIcon, {})
|
|
272
|
+
},
|
|
273
|
+
{
|
|
274
|
+
label: t ? t("rowContextMenu.labelId") : "ID",
|
|
275
|
+
value: id,
|
|
276
|
+
icon: /* @__PURE__ */ jsx(IdCardIcon, {})
|
|
277
|
+
},
|
|
278
|
+
{
|
|
279
|
+
label: t ? t("rowContextMenu.labelUrl") : "URL",
|
|
280
|
+
value: url,
|
|
281
|
+
icon: /* @__PURE__ */ jsx(LinkIcon, {})
|
|
282
|
+
},
|
|
283
|
+
...(extra ?? []).map((e) => ({
|
|
284
|
+
label: e.label,
|
|
285
|
+
value: e.value,
|
|
286
|
+
icon: e.icon ?? /* @__PURE__ */ jsx(CopyIcon, {})
|
|
287
|
+
}))
|
|
288
|
+
].filter((f) => f.value).map((f) => ({
|
|
289
|
+
kind: "action",
|
|
290
|
+
label: t ? t("rowContextMenu.copy", { label: f.label }) : `Copy ${f.label}`,
|
|
291
|
+
icon: f.icon,
|
|
292
|
+
copy: {
|
|
293
|
+
text: f.value,
|
|
294
|
+
label: f.label
|
|
295
|
+
}
|
|
296
|
+
}));
|
|
297
|
+
return {
|
|
298
|
+
kind: "submenu",
|
|
299
|
+
label: t ? t("common.copy") : "Copy",
|
|
300
|
+
icon: /* @__PURE__ */ jsx(ClipboardIcon, {}),
|
|
301
|
+
items
|
|
302
|
+
};
|
|
303
|
+
}
|
|
304
|
+
/** Stays visible while active (menu open) so it doesn't vanish behind the overlay. */
|
|
305
|
+
function MoreButton({ onOpen, active, className }) {
|
|
306
|
+
const { list: t } = useStrings();
|
|
307
|
+
return /* @__PURE__ */ jsx("button", {
|
|
308
|
+
type: "button",
|
|
309
|
+
"aria-label": t.moreActions,
|
|
310
|
+
onClick: (e) => {
|
|
311
|
+
e.stopPropagation();
|
|
312
|
+
const r = e.currentTarget.getBoundingClientRect();
|
|
313
|
+
onOpen(r.right, r.bottom);
|
|
314
|
+
},
|
|
315
|
+
className: cx("rounded p-1 cursor-pointer text-(--theme-muted-text-color) transition-colors hover:bg-(--theme-muted-panel-bg) hover:text-(--theme-app) focus-visible:opacity-100", active ? "opacity-100" : "opacity-0 group-hover:opacity-100", className),
|
|
316
|
+
children: /* @__PURE__ */ jsx(MoreIcon, { className: "h-4 w-4" })
|
|
317
|
+
});
|
|
318
|
+
}
|
|
319
|
+
//#endregion
|
|
320
|
+
//#region src/list/ListTable.tsx
|
|
321
|
+
var NAME_TEXT = "font-medium text-[13px] leading-tight text-(--theme-app) truncate";
|
|
322
|
+
var SUBTITLE_TEXT = "text-xs leading-tight text-(--theme-muted-text-color) truncate";
|
|
323
|
+
/** table-auto + horizontal scroll; the name column has a min-width floor so it can't be crushed. */
|
|
324
|
+
var listTableProps = {
|
|
325
|
+
borderless: true,
|
|
326
|
+
panel: false,
|
|
327
|
+
rounded: false,
|
|
328
|
+
theadClassName: "text-(--theme-muted-text-color)",
|
|
329
|
+
tbodyClassName: "divide-y border-b border-(--theme-border) divide-(--theme-border)",
|
|
330
|
+
className: "table-auto w-full [&_td:first-child]:pl-4 [&_th:first-child]:pl-4 [&_td:last-child]:pr-4 [&_th:last-child]:pr-4"
|
|
331
|
+
};
|
|
332
|
+
/** Widths come only from the header row, so a windowed body cannot shift the
|
|
333
|
+
* columns as different content scrolls into view. */
|
|
334
|
+
var listTableFixedProps = {
|
|
335
|
+
...listTableProps,
|
|
336
|
+
className: listTableProps.className.replace("table-auto", "table-fixed")
|
|
337
|
+
};
|
|
338
|
+
function NameCell({ icon, name, subtitle, href }) {
|
|
339
|
+
const Link = useLink();
|
|
340
|
+
const inner = /* @__PURE__ */ jsxs(Fragment, { children: [icon, /* @__PURE__ */ jsxs("div", {
|
|
341
|
+
className: "min-w-0",
|
|
342
|
+
children: [/* @__PURE__ */ jsx("div", {
|
|
343
|
+
className: NAME_TEXT,
|
|
344
|
+
children: name
|
|
345
|
+
}), subtitle && /* @__PURE__ */ jsx("div", {
|
|
346
|
+
className: SUBTITLE_TEXT,
|
|
347
|
+
children: subtitle
|
|
348
|
+
})]
|
|
349
|
+
})] });
|
|
350
|
+
return /* @__PURE__ */ jsx(Table.Item, {
|
|
351
|
+
className: "py-2.5",
|
|
352
|
+
children: href ? /* @__PURE__ */ jsx(Link, {
|
|
353
|
+
to: href,
|
|
354
|
+
className: "flex items-center gap-2.5 min-w-0 cursor-pointer",
|
|
355
|
+
children: inner
|
|
356
|
+
}) : /* @__PURE__ */ jsx("div", {
|
|
357
|
+
className: "flex items-center gap-2.5 min-w-0",
|
|
358
|
+
children: inner
|
|
359
|
+
})
|
|
360
|
+
});
|
|
361
|
+
}
|
|
362
|
+
function GroupRow({ label, count, colSpan }) {
|
|
363
|
+
return /* @__PURE__ */ jsx("tr", { children: /* @__PURE__ */ jsxs("td", {
|
|
364
|
+
colSpan,
|
|
365
|
+
className: "bg-(--theme-muted-panel-bg) py-1.5 text-xs font-medium",
|
|
366
|
+
children: [
|
|
367
|
+
/* @__PURE__ */ jsx("span", {
|
|
368
|
+
className: "text-(--theme-app)",
|
|
369
|
+
children: label
|
|
370
|
+
}),
|
|
371
|
+
/* @__PURE__ */ jsx("span", {
|
|
372
|
+
className: "mx-1.5 opacity-50",
|
|
373
|
+
children: "·"
|
|
374
|
+
}),
|
|
375
|
+
/* @__PURE__ */ jsx("span", {
|
|
376
|
+
className: "text-(--theme-muted-text-color)",
|
|
377
|
+
children: count
|
|
378
|
+
})
|
|
379
|
+
]
|
|
380
|
+
}) });
|
|
381
|
+
}
|
|
382
|
+
function ListError({ error, noun = "data" }) {
|
|
383
|
+
const { list: t } = useStrings();
|
|
384
|
+
const message = error && typeof error === "object" && "message" in error ? String(error.message) : void 0;
|
|
385
|
+
return /* @__PURE__ */ jsxs("div", {
|
|
386
|
+
className: "flex flex-col items-center justify-center gap-3 py-20 text-center",
|
|
387
|
+
children: [/* @__PURE__ */ jsx(ErrorIcon, { className: "h-10 w-10 text-red-400 opacity-80" }), /* @__PURE__ */ jsxs("div", {
|
|
388
|
+
className: "space-y-1",
|
|
389
|
+
children: [/* @__PURE__ */ jsx("p", {
|
|
390
|
+
className: "text-sm font-medium text-(--theme-app)",
|
|
391
|
+
children: t.couldNotLoad(noun)
|
|
392
|
+
}), message && /* @__PURE__ */ jsx("p", {
|
|
393
|
+
className: "max-w-md text-xs text-(--theme-muted-text-color)",
|
|
394
|
+
children: message
|
|
395
|
+
})]
|
|
396
|
+
})]
|
|
397
|
+
});
|
|
398
|
+
}
|
|
399
|
+
function ListSkeleton({ rows = 6 }) {
|
|
400
|
+
return /* @__PURE__ */ jsx("div", {
|
|
401
|
+
className: "divide-y border-b border-(--theme-border) divide-(--theme-border)",
|
|
402
|
+
children: Array.from({ length: rows }).map((_, i) => /* @__PURE__ */ jsxs("div", {
|
|
403
|
+
className: "flex items-center gap-3 px-4 py-2.5 animate-pulse",
|
|
404
|
+
children: [
|
|
405
|
+
/* @__PURE__ */ jsx("div", { className: "h-5 w-5 rounded bg-(--theme-muted-panel-bg)" }),
|
|
406
|
+
/* @__PURE__ */ jsxs("div", {
|
|
407
|
+
className: "space-y-1.5",
|
|
408
|
+
children: [/* @__PURE__ */ jsx("div", { className: "h-3 w-40 rounded bg-(--theme-muted-panel-bg)" }), /* @__PURE__ */ jsx("div", { className: "h-2.5 w-24 rounded bg-(--theme-muted-panel-bg)" })]
|
|
409
|
+
}),
|
|
410
|
+
/* @__PURE__ */ jsx("div", { className: "ml-auto h-3 w-20 rounded bg-(--theme-muted-panel-bg)" })
|
|
411
|
+
]
|
|
412
|
+
}, i))
|
|
413
|
+
});
|
|
414
|
+
}
|
|
415
|
+
/** Prevents the name column from being crushed under table-auto layout during horizontal overflow. */
|
|
416
|
+
var NAME_MIN_WIDTH_PX = 200;
|
|
417
|
+
/** Trailing cell geometry: icon-button size + gap + padding, sized to fit exactly its pinned buttons. */
|
|
418
|
+
var ACTION_BUTTON_PX = 24;
|
|
419
|
+
var ACTION_GAP_PX = 2;
|
|
420
|
+
var ACTIONS_CELL_PAD_PX = 28;
|
|
421
|
+
/** Width the trailing actions column reserves for `count` always-visible
|
|
422
|
+
* buttons plus the hover `⋯` trigger. */
|
|
423
|
+
function actionsColumnWidth(count) {
|
|
424
|
+
const buttons = count + 1;
|
|
425
|
+
return buttons * ACTION_BUTTON_PX + (buttons - 1) * ACTION_GAP_PX + ACTIONS_CELL_PAD_PX;
|
|
426
|
+
}
|
|
427
|
+
/** Shared leading selection checkbox for multi-select rows: stops the row-click
|
|
428
|
+
* and suppresses shift-click text selection. Wrap in <Table.Item> for `leading`. */
|
|
429
|
+
function RowSelectCheckbox({ checked, label, onToggle }) {
|
|
430
|
+
return /* @__PURE__ */ jsx("input", {
|
|
431
|
+
type: "checkbox",
|
|
432
|
+
"aria-label": label,
|
|
433
|
+
checked,
|
|
434
|
+
onChange: () => {},
|
|
435
|
+
onClick: (e) => {
|
|
436
|
+
e.stopPropagation();
|
|
437
|
+
onToggle(e);
|
|
438
|
+
},
|
|
439
|
+
onMouseDown: (e) => {
|
|
440
|
+
if (e.shiftKey) e.preventDefault();
|
|
441
|
+
},
|
|
442
|
+
className: "h-4 w-4 shrink-0 rounded border-(--theme-border) text-blue-500 focus:ring-blue-500 focus:ring-offset-0 cursor-pointer"
|
|
443
|
+
});
|
|
444
|
+
}
|
|
445
|
+
/** Sizes to fit pinned buttons + ⋯; below ~44rem only ⋯ remains. Pass a view's
|
|
446
|
+
* chrome (structurally: showActions + actionsWidth) or actionCount. */
|
|
447
|
+
function ListActionsHeader({ view, actionCount = 0, className }) {
|
|
448
|
+
if (view && !view.showActions) return null;
|
|
449
|
+
const width = view ? view.actionsWidth : actionsColumnWidth(actionCount);
|
|
450
|
+
return /* @__PURE__ */ jsx(Table.Header, {
|
|
451
|
+
caps: false,
|
|
452
|
+
style: {
|
|
453
|
+
width,
|
|
454
|
+
minWidth: width
|
|
455
|
+
},
|
|
456
|
+
className: cx("py-2 text-right @max-[43rem]:w-[52px]! @max-[43rem]:min-w-[52px]!", className),
|
|
457
|
+
children: /* @__PURE__ */ jsx("span", {
|
|
458
|
+
className: "sr-only",
|
|
459
|
+
children: "Actions"
|
|
460
|
+
})
|
|
461
|
+
});
|
|
462
|
+
}
|
|
463
|
+
ListActionsHeader.isTableHeader = true;
|
|
464
|
+
//#endregion
|
|
465
|
+
export { useRowMenu as _, NAME_MIN_WIDTH_PX as a, actionsColumnWidth as c, MoreButton as d, assembleRowMenu as f, toolbarActionToRowAction as g, toRowMenuItem as h, ListSkeleton as i, listTableFixedProps as l, rowContextMenuProps as m, ListActionsHeader as n, NameCell as o, copySubmenu as p, ListError as r, RowSelectCheckbox as s, GroupRow as t, listTableProps as u, useRowMenuActive as v };
|
|
@@ -0,0 +1,27 @@
|
|
|
1
|
+
import React from 'react';
|
|
2
|
+
interface IControlledCollapsiblePanelProps {
|
|
3
|
+
title?: string | React.ReactNode | ((open: boolean, setOpen: React.Dispatch<React.SetStateAction<boolean>>) => React.ReactNode);
|
|
4
|
+
children: React.ReactNode;
|
|
5
|
+
open: boolean | undefined;
|
|
6
|
+
setOpen?: React.Dispatch<React.SetStateAction<boolean>>;
|
|
7
|
+
onClick?: () => void;
|
|
8
|
+
wrapperElement?: React.ElementType;
|
|
9
|
+
shown?: boolean;
|
|
10
|
+
setShown?: (shown: boolean) => void;
|
|
11
|
+
customizedButton?: React.ReactNode;
|
|
12
|
+
className?: string;
|
|
13
|
+
}
|
|
14
|
+
export declare function ControlledCollapsiblePanel({ title, children, open, setOpen, onClick, wrapperElement, customizedButton, className, }: IControlledCollapsiblePanelProps): React.JSX.Element;
|
|
15
|
+
export declare function UncontrolledCollapsiblePanel({ title, children, onClick, wrapperElement, initialState, className, customizedButton, }: Omit<IControlledCollapsiblePanelProps, 'setOpen' | 'open'> & {
|
|
16
|
+
initialState?: boolean;
|
|
17
|
+
}): React.JSX.Element;
|
|
18
|
+
type MaybeCollapsibleProps = {
|
|
19
|
+
className?: string;
|
|
20
|
+
initialState?: boolean;
|
|
21
|
+
children: React.ReactNode;
|
|
22
|
+
title?: React.ReactNode;
|
|
23
|
+
customizedButton?: React.ReactNode;
|
|
24
|
+
collapsible?: boolean;
|
|
25
|
+
};
|
|
26
|
+
export declare function MaybeCollapsible({ className, initialState, children, title, customizedButton, collapsible, }: MaybeCollapsibleProps): React.JSX.Element;
|
|
27
|
+
export {};
|