@harborclient/sdk 1.0.0 → 1.0.2
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/build/index.d.ts.map +1 -1
- package/dist/build/index.js +10 -1
- package/dist/client.d.ts +2 -2
- package/dist/components/Autocomplete/AutocompleteInput.d.ts +23 -0
- package/dist/components/Autocomplete/AutocompleteInput.d.ts.map +1 -0
- package/dist/components/Autocomplete/AutocompleteInput.js +26 -0
- package/dist/components/Autocomplete/SuggestionList.d.ts +45 -0
- package/dist/components/Autocomplete/SuggestionList.d.ts.map +1 -0
- package/dist/components/Autocomplete/SuggestionList.js +72 -0
- package/dist/components/Autocomplete/index.d.ts +6 -0
- package/dist/components/Autocomplete/index.d.ts.map +1 -0
- package/dist/components/Autocomplete/index.js +3 -0
- package/dist/components/Autocomplete/types.d.ts +19 -0
- package/dist/components/Autocomplete/types.d.ts.map +1 -0
- package/dist/components/Autocomplete/types.js +1 -0
- package/dist/components/Autocomplete/useAutocomplete.d.ts +84 -0
- package/dist/components/Autocomplete/useAutocomplete.d.ts.map +1 -0
- package/dist/components/Autocomplete/useAutocomplete.js +191 -0
- package/dist/components/Button/index.d.ts.map +1 -1
- package/dist/components/Button/index.js +8 -7
- package/dist/components/KeyValueEditor/index.d.ts +10 -1
- package/dist/components/KeyValueEditor/index.d.ts.map +1 -1
- package/dist/components/KeyValueEditor/index.js +4 -3
- package/dist/components/VariableInput/index.d.ts +6 -1
- package/dist/components/VariableInput/index.d.ts.map +1 -1
- package/dist/components/VariableInput/index.js +19 -3
- package/dist/components/index.d.ts +1 -0
- package/dist/components/index.d.ts.map +1 -1
- package/dist/components/index.js +1 -0
- package/dist/components/portalToBody.d.ts +2 -1
- package/dist/components/portalToBody.d.ts.map +1 -1
- package/dist/components/portalToBody.js +5 -4
- package/dist/index.d.ts +1 -1
- package/dist/index.d.ts.map +1 -1
- package/dist/main.d.ts +1 -1
- package/dist/main.d.ts.map +1 -1
- package/dist/runtime/hcBridge.js +0 -3
- package/dist/runtime/index.d.ts +1 -1
- package/dist/runtime/jsx-dev-runtime.d.ts +1 -1
- package/dist/runtime/store.d.ts +6 -1
- package/dist/runtime/store.d.ts.map +1 -1
- package/dist/runtime/store.js +8 -2
- package/dist/runtime/store.ts +11 -3
- package/package.json +3 -2
- package/dist/components/enhanceControl.test.d.ts +0 -2
- package/dist/components/enhanceControl.test.d.ts.map +0 -1
- package/dist/components/enhanceControl.test.js +0 -83
- package/dist/components/utils.test.d.ts +0 -2
- package/dist/components/utils.test.d.ts.map +0 -1
- package/dist/components/utils.test.js +0 -44
- package/dist/http/resolveRequest.test.d.ts +0 -2
- package/dist/http/resolveRequest.test.d.ts.map +0 -1
- package/dist/http/resolveRequest.test.js +0 -41
- package/dist/http/substitute.test.d.ts +0 -2
- package/dist/http/substitute.test.d.ts.map +0 -1
- package/dist/http/substitute.test.js +0 -93
- package/dist/pluginDatabaseApi.test.d.ts +0 -2
- package/dist/pluginDatabaseApi.test.d.ts.map +0 -1
- package/dist/pluginDatabaseApi.test.js +0 -65
- package/dist/runtime/index.test.d.ts +0 -2
- package/dist/runtime/index.test.d.ts.map +0 -1
- package/dist/runtime/index.test.js +0 -41
- package/dist/runtime/index.test.ts +0 -53
- package/dist/runtime-utils.test.d.ts +0 -2
- package/dist/runtime-utils.test.d.ts.map +0 -1
- package/dist/runtime-utils.test.js +0 -177
- package/dist/signing/signing.test.d.ts +0 -2
- package/dist/signing/signing.test.d.ts.map +0 -1
- package/dist/signing/signing.test.js +0 -100
- package/dist/storage/cappedList.test.d.ts +0 -2
- package/dist/storage/cappedList.test.d.ts.map +0 -1
- package/dist/storage/cappedList.test.js +0 -11
- package/dist/storage/validate.test.d.ts +0 -2
- package/dist/storage/validate.test.d.ts.map +0 -1
- package/dist/storage/validate.test.js +0 -78
- package/dist/store.test.d.ts +0 -2
- package/dist/store.test.d.ts.map +0 -1
- package/dist/store.test.js +0 -248
- package/dist/utilities.test.d.ts +0 -2
- package/dist/utilities.test.d.ts.map +0 -1
- package/dist/utilities.test.js +0 -16
- package/dist/variables/dynamic.test.d.ts +0 -2
- package/dist/variables/dynamic.test.d.ts.map +0 -1
- package/dist/variables/dynamic.test.js +0 -60
- package/dist/variables/tokens.test.d.ts +0 -2
- package/dist/variables/tokens.test.d.ts.map +0 -1
- package/dist/variables/tokens.test.js +0 -160
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"index.d.ts","sourceRoot":"","sources":["../../src/build/index.ts"],"names":[],"mappings":"AAGA,OAAO,KAAK,EAAE,YAAY,EAAE,MAAM,EAAE,MAAM,SAAS,CAAC;AAEpD;;;;;;;;GAQG;AACH,MAAM,MAAM,cAAc,GAAG,MAAM,GAAG,SAAS,GAAG,WAAW,GAAG,MAAM,CAAC;AAEvE;;GAEG;AACH,MAAM,WAAW,oBAAoB;IACnC,2DAA2D;IAC3D,KAAK,CAAC,EAAE,MAAM,CAAC;IACf,0DAA0D;IAC1D,OAAO,CAAC,EAAE,MAAM,CAAC;IACjB,gEAAgE;IAChE,KAAK,CAAC,EAAE,OAAO,CAAC;IAChB,gEAAgE;IAChE,UAAU,CAAC,EAAE,cAAc,CAAC;IAC5B,iEAAiE;IACjE,QAAQ,CAAC,EAAE,MAAM,EAAE,CAAC;IACpB,2DAA2D;IAC3D,MAAM,CAAC,EAAE,MAAM,CAAC,MAAM,EAAE,MAAM,CAAC,CAAC;IAChC,6DAA6D;IAC7D,OAAO,CAAC,EAAE,MAAM,EAAE,CAAC;IACnB;;;OAGG;IACH,YAAY,CAAC,EAAE,MAAM,CAAC;IACtB,6CAA6C;IAC7C,QAAQ,CAAC,EAAE,YAAY,CAAC,UAAU,CAAC,CAAC;IACpC;;;OAGG;IACH,IAAI,CAAC,EAAE,aAAa,CAAC,SAAS,CAAC,MAAM,EAAE,MAAM,CAAC,CAAC,CAAC;CACjD;AAwCD;;;;GAIG;AACH,wBAAsB,aAAa,CAAC,OAAO,GAAE,oBAAyB,GAAG,OAAO,CAAC,IAAI,CAAC,CAqDrF;
|
|
1
|
+
{"version":3,"file":"index.d.ts","sourceRoot":"","sources":["../../src/build/index.ts"],"names":[],"mappings":"AAGA,OAAO,KAAK,EAAE,YAAY,EAAE,MAAM,EAAE,MAAM,SAAS,CAAC;AAEpD;;;;;;;;GAQG;AACH,MAAM,MAAM,cAAc,GAAG,MAAM,GAAG,SAAS,GAAG,WAAW,GAAG,MAAM,CAAC;AAEvE;;GAEG;AACH,MAAM,WAAW,oBAAoB;IACnC,2DAA2D;IAC3D,KAAK,CAAC,EAAE,MAAM,CAAC;IACf,0DAA0D;IAC1D,OAAO,CAAC,EAAE,MAAM,CAAC;IACjB,gEAAgE;IAChE,KAAK,CAAC,EAAE,OAAO,CAAC;IAChB,gEAAgE;IAChE,UAAU,CAAC,EAAE,cAAc,CAAC;IAC5B,iEAAiE;IACjE,QAAQ,CAAC,EAAE,MAAM,EAAE,CAAC;IACpB,2DAA2D;IAC3D,MAAM,CAAC,EAAE,MAAM,CAAC,MAAM,EAAE,MAAM,CAAC,CAAC;IAChC,6DAA6D;IAC7D,OAAO,CAAC,EAAE,MAAM,EAAE,CAAC;IACnB;;;OAGG;IACH,YAAY,CAAC,EAAE,MAAM,CAAC;IACtB,6CAA6C;IAC7C,QAAQ,CAAC,EAAE,YAAY,CAAC,UAAU,CAAC,CAAC;IACpC;;;OAGG;IACH,IAAI,CAAC,EAAE,aAAa,CAAC,SAAS,CAAC,MAAM,EAAE,MAAM,CAAC,CAAC,CAAC;CACjD;AAwCD;;;;GAIG;AACH,wBAAsB,aAAa,CAAC,OAAO,GAAE,oBAAyB,GAAG,OAAO,CAAC,IAAI,CAAC,CAqDrF;AAYD;;;;;;;;GAQG;AACH,wBAAgB,sBAAsB,CAAC,WAAW,EAAE,SAAS,MAAM,EAAE,GAAG,MAAM,CAiB7E"}
|
package/dist/build/index.js
CHANGED
|
@@ -79,6 +79,15 @@ export async function buildRenderer(options = {}) {
|
|
|
79
79
|
copyAssets(copy);
|
|
80
80
|
}
|
|
81
81
|
}
|
|
82
|
+
/**
|
|
83
|
+
* Escapes a string for use as a literal in a RegExp.
|
|
84
|
+
*
|
|
85
|
+
* @param value - Raw string to escape.
|
|
86
|
+
* @returns Regex-safe literal.
|
|
87
|
+
*/
|
|
88
|
+
function escapeRegExp(value) {
|
|
89
|
+
return value.replace(/[.*+?^${}()|[\]\\]/g, '\\$&');
|
|
90
|
+
}
|
|
82
91
|
/**
|
|
83
92
|
* esbuild plugin that stubs Node built-in modules with empty exports.
|
|
84
93
|
*
|
|
@@ -93,7 +102,7 @@ export function nodeBuiltinStubsPlugin(moduleNames) {
|
|
|
93
102
|
name: 'node-builtins-stub',
|
|
94
103
|
setup(build) {
|
|
95
104
|
for (const moduleName of moduleNames) {
|
|
96
|
-
build.onResolve({ filter: new RegExp(`^${moduleName}$`) }, () => ({
|
|
105
|
+
build.onResolve({ filter: new RegExp(`^${escapeRegExp(moduleName)}$`) }, () => ({
|
|
97
106
|
path: moduleName,
|
|
98
107
|
namespace: 'node-stub'
|
|
99
108
|
}));
|
package/dist/client.d.ts
CHANGED
|
@@ -1,2 +1,2 @@
|
|
|
1
|
-
export * from './index';
|
|
2
|
-
export * from './runtime/index';
|
|
1
|
+
export * from './index.js';
|
|
2
|
+
export * from './runtime/index.js';
|
|
@@ -0,0 +1,23 @@
|
|
|
1
|
+
import type { InputHTMLAttributes, JSX } from 'react';
|
|
2
|
+
import type { AutocompleteSource } from './types.js';
|
|
3
|
+
export interface Props extends Omit<InputHTMLAttributes<HTMLInputElement>, 'value' | 'onChange'> {
|
|
4
|
+
/**
|
|
5
|
+
* Current input value.
|
|
6
|
+
*/
|
|
7
|
+
value: string;
|
|
8
|
+
/**
|
|
9
|
+
* Called when the value changes.
|
|
10
|
+
*
|
|
11
|
+
* @param value - Updated input value.
|
|
12
|
+
*/
|
|
13
|
+
onChange: (value: string) => void;
|
|
14
|
+
/**
|
|
15
|
+
* Optional async source for suggestions and persistence.
|
|
16
|
+
*/
|
|
17
|
+
source?: AutocompleteSource;
|
|
18
|
+
}
|
|
19
|
+
/**
|
|
20
|
+
* Text input with optional async autocomplete suggestions.
|
|
21
|
+
*/
|
|
22
|
+
export declare function AutocompleteInput({ value, onChange, source, className, onFocus, onBlur, onKeyDown, ...props }: Props): JSX.Element;
|
|
23
|
+
//# sourceMappingURL=AutocompleteInput.d.ts.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"AutocompleteInput.d.ts","sourceRoot":"","sources":["../../../src/components/Autocomplete/AutocompleteInput.tsx"],"names":[],"mappings":"AAAA,OAAO,KAAK,EAAE,mBAAmB,EAAE,GAAG,EAAE,MAAM,OAAO,CAAC;AAGtD,OAAO,KAAK,EAAE,kBAAkB,EAAE,MAAM,YAAY,CAAC;AAGrD,MAAM,WAAW,KAAM,SAAQ,IAAI,CAAC,mBAAmB,CAAC,gBAAgB,CAAC,EAAE,OAAO,GAAG,UAAU,CAAC;IAC9F;;OAEG;IACH,KAAK,EAAE,MAAM,CAAC;IAEd;;;;OAIG;IACH,QAAQ,EAAE,CAAC,KAAK,EAAE,MAAM,KAAK,IAAI,CAAC;IAElC;;OAEG;IACH,MAAM,CAAC,EAAE,kBAAkB,CAAC;CAC7B;AAED;;GAEG;AACH,wBAAgB,iBAAiB,CAAC,EAChC,KAAK,EACL,QAAQ,EACR,MAAM,EACN,SAAS,EACT,OAAO,EACP,MAAM,EACN,SAAS,EACT,GAAG,KAAK,EACT,EAAE,KAAK,GAAG,GAAG,CAAC,OAAO,CAgErB"}
|
|
@@ -0,0 +1,26 @@
|
|
|
1
|
+
import { jsx as _jsx, Fragment as _Fragment, jsxs as _jsxs } from "@harborclient/sdk/jsx-runtime";
|
|
2
|
+
import { Input } from '../forms/index.js';
|
|
3
|
+
import { SuggestionList } from './SuggestionList.js';
|
|
4
|
+
import { useAutocomplete } from './useAutocomplete.js';
|
|
5
|
+
/**
|
|
6
|
+
* Text input with optional async autocomplete suggestions.
|
|
7
|
+
*/
|
|
8
|
+
export function AutocompleteInput({ value, onChange, source, className, onFocus, onBlur, onKeyDown, ...props }) {
|
|
9
|
+
const { open, items, activeIndex, anchorRef, listboxId, onFocus: openAutocomplete, onBlur: closeAutocomplete, onInputKeyDown, selectItem, setActiveIndex, closeSuggestions } = useAutocomplete({
|
|
10
|
+
source,
|
|
11
|
+
value,
|
|
12
|
+
onSelect: onChange
|
|
13
|
+
});
|
|
14
|
+
return (_jsxs(_Fragment, { children: [_jsx(Input, { ...props, ref: anchorRef, role: source ? 'combobox' : undefined, "aria-autocomplete": source ? 'list' : undefined, "aria-expanded": source ? open : undefined, "aria-controls": source && open ? listboxId : undefined, "aria-activedescendant": source && open && activeIndex >= 0 ? `${listboxId}-option-${activeIndex}` : undefined, className: className, value: value, onChange: (event) => onChange(event.target.value), onFocus: (event) => {
|
|
15
|
+
openAutocomplete();
|
|
16
|
+
onFocus?.(event);
|
|
17
|
+
}, onBlur: (event) => {
|
|
18
|
+
closeAutocomplete();
|
|
19
|
+
onBlur?.(event);
|
|
20
|
+
}, onKeyDown: (event) => {
|
|
21
|
+
if (onInputKeyDown(event)) {
|
|
22
|
+
return;
|
|
23
|
+
}
|
|
24
|
+
onKeyDown?.(event);
|
|
25
|
+
} }), source && (_jsx(SuggestionList, { open: open, items: items, activeIndex: activeIndex, anchorRef: anchorRef, listboxId: listboxId, onSelect: selectItem, onActiveIndexChange: setActiveIndex, onClose: closeSuggestions }))] }));
|
|
26
|
+
}
|
|
@@ -0,0 +1,45 @@
|
|
|
1
|
+
import type { JSX, RefObject } from 'react';
|
|
2
|
+
interface SuggestionListProps {
|
|
3
|
+
/**
|
|
4
|
+
* Whether the suggestion popup should render.
|
|
5
|
+
*/
|
|
6
|
+
open: boolean;
|
|
7
|
+
/**
|
|
8
|
+
* Filtered suggestion values.
|
|
9
|
+
*/
|
|
10
|
+
items: string[];
|
|
11
|
+
/**
|
|
12
|
+
* Keyboard-highlighted suggestion index.
|
|
13
|
+
*/
|
|
14
|
+
activeIndex: number;
|
|
15
|
+
/**
|
|
16
|
+
* Anchor input used to position the popup.
|
|
17
|
+
*/
|
|
18
|
+
anchorRef: RefObject<HTMLElement | null>;
|
|
19
|
+
/**
|
|
20
|
+
* Id of the listbox element for aria-controls wiring.
|
|
21
|
+
*/
|
|
22
|
+
listboxId: string;
|
|
23
|
+
/**
|
|
24
|
+
* Called when the user selects a suggestion.
|
|
25
|
+
*
|
|
26
|
+
* @param item - Selected suggestion value.
|
|
27
|
+
*/
|
|
28
|
+
onSelect: (item: string) => void;
|
|
29
|
+
/**
|
|
30
|
+
* Called when the active highlight changes via mouse hover.
|
|
31
|
+
*
|
|
32
|
+
* @param index - Highlighted suggestion index.
|
|
33
|
+
*/
|
|
34
|
+
onActiveIndexChange: (index: number) => void;
|
|
35
|
+
/**
|
|
36
|
+
* Called when the popup should close (outside click).
|
|
37
|
+
*/
|
|
38
|
+
onClose: () => void;
|
|
39
|
+
}
|
|
40
|
+
/**
|
|
41
|
+
* Portaled suggestion list for combobox autocomplete inputs.
|
|
42
|
+
*/
|
|
43
|
+
export declare function SuggestionList({ open, items, activeIndex, anchorRef, listboxId, onSelect, onActiveIndexChange, onClose }: SuggestionListProps): JSX.Element | null;
|
|
44
|
+
export {};
|
|
45
|
+
//# sourceMappingURL=SuggestionList.d.ts.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"SuggestionList.d.ts","sourceRoot":"","sources":["../../../src/components/Autocomplete/SuggestionList.tsx"],"names":[],"mappings":"AACA,OAAO,KAAK,EAAE,GAAG,EAAE,SAAS,EAAE,MAAM,OAAO,CAAC;AAG5C,UAAU,mBAAmB;IAC3B;;OAEG;IACH,IAAI,EAAE,OAAO,CAAC;IAEd;;OAEG;IACH,KAAK,EAAE,MAAM,EAAE,CAAC;IAEhB;;OAEG;IACH,WAAW,EAAE,MAAM,CAAC;IAEpB;;OAEG;IACH,SAAS,EAAE,SAAS,CAAC,WAAW,GAAG,IAAI,CAAC,CAAC;IAEzC;;OAEG;IACH,SAAS,EAAE,MAAM,CAAC;IAElB;;;;OAIG;IACH,QAAQ,EAAE,CAAC,IAAI,EAAE,MAAM,KAAK,IAAI,CAAC;IAEjC;;;;OAIG;IACH,mBAAmB,EAAE,CAAC,KAAK,EAAE,MAAM,KAAK,IAAI,CAAC;IAE7C;;OAEG;IACH,OAAO,EAAE,MAAM,IAAI,CAAC;CACrB;AA0BD;;GAEG;AACH,wBAAgB,cAAc,CAAC,EAC7B,IAAI,EACJ,KAAK,EACL,WAAW,EACX,SAAS,EACT,SAAS,EACT,QAAQ,EACR,mBAAmB,EACnB,OAAO,EACR,EAAE,mBAAmB,GAAG,GAAG,CAAC,OAAO,GAAG,IAAI,CAoF1C"}
|
|
@@ -0,0 +1,72 @@
|
|
|
1
|
+
import { jsx as _jsx } from "@harborclient/sdk/jsx-runtime";
|
|
2
|
+
import { useEffect, useState } from '@harborclient/sdk/react';
|
|
3
|
+
import { portalToBody } from '../portalToBody.js';
|
|
4
|
+
/**
|
|
5
|
+
* Computes fixed popup coordinates from the anchor element.
|
|
6
|
+
*
|
|
7
|
+
* @param anchor - Anchor element for positioning.
|
|
8
|
+
*/
|
|
9
|
+
function getPopupPosition(anchor) {
|
|
10
|
+
if (!anchor) {
|
|
11
|
+
return null;
|
|
12
|
+
}
|
|
13
|
+
const rect = anchor.getBoundingClientRect();
|
|
14
|
+
return {
|
|
15
|
+
top: rect.bottom + 2,
|
|
16
|
+
left: rect.left,
|
|
17
|
+
width: rect.width
|
|
18
|
+
};
|
|
19
|
+
}
|
|
20
|
+
/**
|
|
21
|
+
* Portaled suggestion list for combobox autocomplete inputs.
|
|
22
|
+
*/
|
|
23
|
+
export function SuggestionList({ open, items, activeIndex, anchorRef, listboxId, onSelect, onActiveIndexChange, onClose }) {
|
|
24
|
+
const [position, setPosition] = useState(null);
|
|
25
|
+
useEffect(() => {
|
|
26
|
+
if (!open) {
|
|
27
|
+
setPosition(null);
|
|
28
|
+
return;
|
|
29
|
+
}
|
|
30
|
+
/**
|
|
31
|
+
* Updates popup position from the anchor rect.
|
|
32
|
+
*/
|
|
33
|
+
const updatePosition = () => {
|
|
34
|
+
setPosition(getPopupPosition(anchorRef.current));
|
|
35
|
+
};
|
|
36
|
+
updatePosition();
|
|
37
|
+
window.addEventListener('scroll', updatePosition, true);
|
|
38
|
+
window.addEventListener('resize', updatePosition);
|
|
39
|
+
return () => {
|
|
40
|
+
window.removeEventListener('scroll', updatePosition, true);
|
|
41
|
+
window.removeEventListener('resize', updatePosition);
|
|
42
|
+
};
|
|
43
|
+
}, [anchorRef, open]);
|
|
44
|
+
useEffect(() => {
|
|
45
|
+
if (!open) {
|
|
46
|
+
return;
|
|
47
|
+
}
|
|
48
|
+
/**
|
|
49
|
+
* Closes the popup when the user clicks outside the anchor and list.
|
|
50
|
+
*/
|
|
51
|
+
const handlePointerDown = (event) => {
|
|
52
|
+
const target = event.target;
|
|
53
|
+
if (!(target instanceof Node)) {
|
|
54
|
+
return;
|
|
55
|
+
}
|
|
56
|
+
const anchor = anchorRef.current;
|
|
57
|
+
const listbox = document.getElementById(listboxId);
|
|
58
|
+
if (anchor?.contains(target) || listbox?.contains(target)) {
|
|
59
|
+
return;
|
|
60
|
+
}
|
|
61
|
+
onClose();
|
|
62
|
+
};
|
|
63
|
+
document.addEventListener('pointerdown', handlePointerDown);
|
|
64
|
+
return () => document.removeEventListener('pointerdown', handlePointerDown);
|
|
65
|
+
}, [anchorRef, listboxId, onClose, open]);
|
|
66
|
+
if (!open || items.length === 0 || !position) {
|
|
67
|
+
return null;
|
|
68
|
+
}
|
|
69
|
+
return portalToBody(_jsx("ul", { id: listboxId, role: "listbox", className: "fixed z-50 max-h-48 overflow-y-auto rounded-md border border-separator bg-surface py-1 text-[14px] text-text shadow-md", style: { top: position.top, left: position.left, width: position.width }, children: items.map((item, index) => (_jsx("li", { id: `${listboxId}-option-${index}`, role: "option", "aria-selected": index === activeIndex, className: index === activeIndex
|
|
70
|
+
? 'cursor-pointer bg-selection px-2 py-1'
|
|
71
|
+
: 'cursor-pointer px-2 py-1 hover:bg-selection', onMouseEnter: () => onActiveIndexChange(index), onMouseDown: (event) => event.preventDefault(), onClick: () => onSelect(item), children: item }, item))) }));
|
|
72
|
+
}
|
|
@@ -0,0 +1,6 @@
|
|
|
1
|
+
export { AutocompleteInput } from './AutocompleteInput.js';
|
|
2
|
+
export type { Props as AutocompleteInputProps } from './AutocompleteInput.js';
|
|
3
|
+
export { SuggestionList } from './SuggestionList.js';
|
|
4
|
+
export type { AutocompleteSource } from './types.js';
|
|
5
|
+
export { useAutocomplete } from './useAutocomplete.js';
|
|
6
|
+
//# sourceMappingURL=index.d.ts.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"index.d.ts","sourceRoot":"","sources":["../../../src/components/Autocomplete/index.ts"],"names":[],"mappings":"AAAA,OAAO,EAAE,iBAAiB,EAAE,MAAM,wBAAwB,CAAC;AAC3D,YAAY,EAAE,KAAK,IAAI,sBAAsB,EAAE,MAAM,wBAAwB,CAAC;AAC9E,OAAO,EAAE,cAAc,EAAE,MAAM,qBAAqB,CAAC;AACrD,YAAY,EAAE,kBAAkB,EAAE,MAAM,YAAY,CAAC;AACrD,OAAO,EAAE,eAAe,EAAE,MAAM,sBAAsB,CAAC"}
|
|
@@ -0,0 +1,19 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* Async provider for autocomplete suggestions.
|
|
3
|
+
*
|
|
4
|
+
* {@link list} returns known values; {@link add} persists a new value when the user
|
|
5
|
+
* commits text that is not already in the list.
|
|
6
|
+
*/
|
|
7
|
+
export interface AutocompleteSource {
|
|
8
|
+
/**
|
|
9
|
+
* Returns all known autocomplete values.
|
|
10
|
+
*/
|
|
11
|
+
list(): Promise<string[]>;
|
|
12
|
+
/**
|
|
13
|
+
* Persists a new autocomplete value for future {@link list} calls.
|
|
14
|
+
*
|
|
15
|
+
* @param value - Trimmed value committed by the user.
|
|
16
|
+
*/
|
|
17
|
+
add(value: string): Promise<void>;
|
|
18
|
+
}
|
|
19
|
+
//# sourceMappingURL=types.d.ts.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"types.d.ts","sourceRoot":"","sources":["../../../src/components/Autocomplete/types.ts"],"names":[],"mappings":"AAAA;;;;;GAKG;AACH,MAAM,WAAW,kBAAkB;IACjC;;OAEG;IACH,IAAI,IAAI,OAAO,CAAC,MAAM,EAAE,CAAC,CAAC;IAE1B;;;;OAIG;IACH,GAAG,CAAC,KAAK,EAAE,MAAM,GAAG,OAAO,CAAC,IAAI,CAAC,CAAC;CACnC"}
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
export {};
|
|
@@ -0,0 +1,84 @@
|
|
|
1
|
+
import type { KeyboardEvent, RefObject } from 'react';
|
|
2
|
+
import type { AutocompleteSource } from './types.js';
|
|
3
|
+
interface UseAutocompleteOptions {
|
|
4
|
+
/**
|
|
5
|
+
* Optional async source for suggestions and persistence.
|
|
6
|
+
*/
|
|
7
|
+
source?: AutocompleteSource;
|
|
8
|
+
/**
|
|
9
|
+
* Current input value.
|
|
10
|
+
*/
|
|
11
|
+
value: string;
|
|
12
|
+
/**
|
|
13
|
+
* Called when the user selects a suggestion from the list.
|
|
14
|
+
*
|
|
15
|
+
* @param item - Selected suggestion value.
|
|
16
|
+
*/
|
|
17
|
+
onSelect: (item: string) => void;
|
|
18
|
+
/**
|
|
19
|
+
* Optional ref for the anchor input; created internally when omitted.
|
|
20
|
+
*/
|
|
21
|
+
anchorRef?: RefObject<HTMLInputElement | null>;
|
|
22
|
+
}
|
|
23
|
+
interface UseAutocompleteResult {
|
|
24
|
+
/**
|
|
25
|
+
* Whether the suggestion popup is visible.
|
|
26
|
+
*/
|
|
27
|
+
open: boolean;
|
|
28
|
+
/**
|
|
29
|
+
* Filtered suggestion items for the current value.
|
|
30
|
+
*/
|
|
31
|
+
items: string[];
|
|
32
|
+
/**
|
|
33
|
+
* Keyboard-highlighted suggestion index, or -1 when none.
|
|
34
|
+
*/
|
|
35
|
+
activeIndex: number;
|
|
36
|
+
/**
|
|
37
|
+
* Ref attached to the anchor input element.
|
|
38
|
+
*/
|
|
39
|
+
anchorRef: RefObject<HTMLInputElement | null>;
|
|
40
|
+
/**
|
|
41
|
+
* Id for the suggestion listbox element.
|
|
42
|
+
*/
|
|
43
|
+
listboxId: string;
|
|
44
|
+
/**
|
|
45
|
+
* Opens suggestions and loads the source list when needed.
|
|
46
|
+
*/
|
|
47
|
+
onFocus: () => void;
|
|
48
|
+
/**
|
|
49
|
+
* Commits the value and closes suggestions.
|
|
50
|
+
*/
|
|
51
|
+
onBlur: () => void;
|
|
52
|
+
/**
|
|
53
|
+
* Handles keyboard navigation for the suggestion list.
|
|
54
|
+
*
|
|
55
|
+
* @returns True when the key was consumed by autocomplete handling.
|
|
56
|
+
*/
|
|
57
|
+
onInputKeyDown: (event: KeyboardEvent<HTMLInputElement>) => boolean;
|
|
58
|
+
/**
|
|
59
|
+
* Selects a suggestion and closes the list.
|
|
60
|
+
*
|
|
61
|
+
* @param item - Suggestion value to apply.
|
|
62
|
+
*/
|
|
63
|
+
selectItem: (item: string) => void;
|
|
64
|
+
/**
|
|
65
|
+
* Re-evaluates filtered items when the input value changes while open.
|
|
66
|
+
*/
|
|
67
|
+
refreshItems: () => void;
|
|
68
|
+
/**
|
|
69
|
+
* Updates the keyboard-highlighted suggestion index.
|
|
70
|
+
*/
|
|
71
|
+
setActiveIndex: (index: number) => void;
|
|
72
|
+
/**
|
|
73
|
+
* Closes the suggestion list without committing.
|
|
74
|
+
*/
|
|
75
|
+
closeSuggestions: () => void;
|
|
76
|
+
}
|
|
77
|
+
/**
|
|
78
|
+
* Headless autocomplete state for combobox inputs.
|
|
79
|
+
*
|
|
80
|
+
* @param options - Source, value, and selection callback.
|
|
81
|
+
*/
|
|
82
|
+
export declare function useAutocomplete({ source, value, onSelect, anchorRef: externalAnchorRef }: UseAutocompleteOptions): UseAutocompleteResult;
|
|
83
|
+
export {};
|
|
84
|
+
//# sourceMappingURL=useAutocomplete.d.ts.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"useAutocomplete.d.ts","sourceRoot":"","sources":["../../../src/components/Autocomplete/useAutocomplete.ts"],"names":[],"mappings":"AACA,OAAO,KAAK,EAAE,aAAa,EAAE,SAAS,EAAE,MAAM,OAAO,CAAC;AACtD,OAAO,KAAK,EAAE,kBAAkB,EAAE,MAAM,YAAY,CAAC;AAErD,UAAU,sBAAsB;IAC9B;;OAEG;IACH,MAAM,CAAC,EAAE,kBAAkB,CAAC;IAE5B;;OAEG;IACH,KAAK,EAAE,MAAM,CAAC;IAEd;;;;OAIG;IACH,QAAQ,EAAE,CAAC,IAAI,EAAE,MAAM,KAAK,IAAI,CAAC;IAEjC;;OAEG;IACH,SAAS,CAAC,EAAE,SAAS,CAAC,gBAAgB,GAAG,IAAI,CAAC,CAAC;CAChD;AAED,UAAU,qBAAqB;IAC7B;;OAEG;IACH,IAAI,EAAE,OAAO,CAAC;IAEd;;OAEG;IACH,KAAK,EAAE,MAAM,EAAE,CAAC;IAEhB;;OAEG;IACH,WAAW,EAAE,MAAM,CAAC;IAEpB;;OAEG;IACH,SAAS,EAAE,SAAS,CAAC,gBAAgB,GAAG,IAAI,CAAC,CAAC;IAE9C;;OAEG;IACH,SAAS,EAAE,MAAM,CAAC;IAElB;;OAEG;IACH,OAAO,EAAE,MAAM,IAAI,CAAC;IAEpB;;OAEG;IACH,MAAM,EAAE,MAAM,IAAI,CAAC;IAEnB;;;;OAIG;IACH,cAAc,EAAE,CAAC,KAAK,EAAE,aAAa,CAAC,gBAAgB,CAAC,KAAK,OAAO,CAAC;IAEpE;;;;OAIG;IACH,UAAU,EAAE,CAAC,IAAI,EAAE,MAAM,KAAK,IAAI,CAAC;IAEnC;;OAEG;IACH,YAAY,EAAE,MAAM,IAAI,CAAC;IAEzB;;OAEG;IACH,cAAc,EAAE,CAAC,KAAK,EAAE,MAAM,KAAK,IAAI,CAAC;IAExC;;OAEG;IACH,gBAAgB,EAAE,MAAM,IAAI,CAAC;CAC9B;AAuBD;;;;GAIG;AACH,wBAAgB,eAAe,CAAC,EAC9B,MAAM,EACN,KAAK,EACL,QAAQ,EACR,SAAS,EAAE,iBAAiB,EAC7B,EAAE,sBAAsB,GAAG,qBAAqB,CAgMhD"}
|
|
@@ -0,0 +1,191 @@
|
|
|
1
|
+
import { useCallback, useEffect, useId, useRef, useState } from '@harborclient/sdk/react';
|
|
2
|
+
/**
|
|
3
|
+
* Filters cached suggestions by the current input value.
|
|
4
|
+
*
|
|
5
|
+
* @param items - Full suggestion list.
|
|
6
|
+
* @param value - Current input value.
|
|
7
|
+
*/
|
|
8
|
+
function filterItems(items, value) {
|
|
9
|
+
const trimmed = value.trim();
|
|
10
|
+
const lower = trimmed.toLowerCase();
|
|
11
|
+
return items.filter((item) => {
|
|
12
|
+
if (item.toLowerCase() === lower) {
|
|
13
|
+
return false;
|
|
14
|
+
}
|
|
15
|
+
if (!trimmed) {
|
|
16
|
+
return true;
|
|
17
|
+
}
|
|
18
|
+
return item.toLowerCase().includes(lower);
|
|
19
|
+
});
|
|
20
|
+
}
|
|
21
|
+
/**
|
|
22
|
+
* Headless autocomplete state for combobox inputs.
|
|
23
|
+
*
|
|
24
|
+
* @param options - Source, value, and selection callback.
|
|
25
|
+
*/
|
|
26
|
+
export function useAutocomplete({ source, value, onSelect, anchorRef: externalAnchorRef }) {
|
|
27
|
+
const internalAnchorRef = useRef(null);
|
|
28
|
+
const anchorRef = externalAnchorRef ?? internalAnchorRef;
|
|
29
|
+
const cacheRef = useRef([]);
|
|
30
|
+
const loadedRef = useRef(false);
|
|
31
|
+
const loadPromiseRef = useRef(null);
|
|
32
|
+
const listboxId = useId();
|
|
33
|
+
const [open, setOpen] = useState(false);
|
|
34
|
+
const [items, setItems] = useState([]);
|
|
35
|
+
const [activeIndex, setActiveIndex] = useState(-1);
|
|
36
|
+
/**
|
|
37
|
+
* Loads suggestions from the source when not already cached.
|
|
38
|
+
*/
|
|
39
|
+
const ensureLoaded = useCallback(async () => {
|
|
40
|
+
if (!source) {
|
|
41
|
+
return [];
|
|
42
|
+
}
|
|
43
|
+
if (loadedRef.current) {
|
|
44
|
+
return cacheRef.current;
|
|
45
|
+
}
|
|
46
|
+
if (loadPromiseRef.current) {
|
|
47
|
+
return loadPromiseRef.current;
|
|
48
|
+
}
|
|
49
|
+
loadPromiseRef.current = source.list().then((list) => {
|
|
50
|
+
cacheRef.current = list;
|
|
51
|
+
loadedRef.current = true;
|
|
52
|
+
loadPromiseRef.current = null;
|
|
53
|
+
return list;
|
|
54
|
+
});
|
|
55
|
+
return loadPromiseRef.current;
|
|
56
|
+
}, [source]);
|
|
57
|
+
/**
|
|
58
|
+
* Updates filtered items from the cached list.
|
|
59
|
+
*/
|
|
60
|
+
const refreshItems = useCallback(() => {
|
|
61
|
+
if (!source) {
|
|
62
|
+
setItems([]);
|
|
63
|
+
return;
|
|
64
|
+
}
|
|
65
|
+
setItems(filterItems(cacheRef.current, value));
|
|
66
|
+
}, [source, value]);
|
|
67
|
+
/**
|
|
68
|
+
* Persists a new value when it is not already known.
|
|
69
|
+
*/
|
|
70
|
+
const commit = useCallback(async () => {
|
|
71
|
+
if (!source) {
|
|
72
|
+
return;
|
|
73
|
+
}
|
|
74
|
+
const trimmed = value.trim();
|
|
75
|
+
if (!trimmed) {
|
|
76
|
+
return;
|
|
77
|
+
}
|
|
78
|
+
const exists = cacheRef.current.some((item) => item.toLowerCase() === trimmed.toLowerCase());
|
|
79
|
+
if (exists) {
|
|
80
|
+
return;
|
|
81
|
+
}
|
|
82
|
+
cacheRef.current = [...cacheRef.current, trimmed];
|
|
83
|
+
try {
|
|
84
|
+
await source.add(trimmed);
|
|
85
|
+
}
|
|
86
|
+
catch {
|
|
87
|
+
cacheRef.current = cacheRef.current.filter((item) => item !== trimmed);
|
|
88
|
+
}
|
|
89
|
+
}, [source, value]);
|
|
90
|
+
/**
|
|
91
|
+
* Opens the suggestion list and loads items when a source is configured.
|
|
92
|
+
*/
|
|
93
|
+
const openSuggestions = useCallback(async () => {
|
|
94
|
+
if (!source) {
|
|
95
|
+
return;
|
|
96
|
+
}
|
|
97
|
+
await ensureLoaded();
|
|
98
|
+
const filtered = filterItems(cacheRef.current, value);
|
|
99
|
+
setItems(filtered);
|
|
100
|
+
setActiveIndex(filtered.length > 0 ? 0 : -1);
|
|
101
|
+
setOpen(true);
|
|
102
|
+
}, [ensureLoaded, source, value]);
|
|
103
|
+
/**
|
|
104
|
+
* Closes the suggestion list and resets highlight state.
|
|
105
|
+
*/
|
|
106
|
+
const closeSuggestions = useCallback(() => {
|
|
107
|
+
setOpen(false);
|
|
108
|
+
setActiveIndex(-1);
|
|
109
|
+
}, []);
|
|
110
|
+
/**
|
|
111
|
+
* Applies a suggestion and closes the list without calling add().
|
|
112
|
+
*
|
|
113
|
+
* @param item - Selected suggestion value.
|
|
114
|
+
*/
|
|
115
|
+
const selectItem = useCallback((item) => {
|
|
116
|
+
onSelect(item);
|
|
117
|
+
closeSuggestions();
|
|
118
|
+
}, [closeSuggestions, onSelect]);
|
|
119
|
+
/**
|
|
120
|
+
* Opens suggestions when the input receives focus.
|
|
121
|
+
*/
|
|
122
|
+
const onFocus = useCallback(() => {
|
|
123
|
+
void openSuggestions();
|
|
124
|
+
}, [openSuggestions]);
|
|
125
|
+
/**
|
|
126
|
+
* Commits new values and closes suggestions on blur.
|
|
127
|
+
*/
|
|
128
|
+
const onBlur = useCallback(() => {
|
|
129
|
+
void commit();
|
|
130
|
+
closeSuggestions();
|
|
131
|
+
}, [closeSuggestions, commit]);
|
|
132
|
+
/**
|
|
133
|
+
* Handles arrow keys, Enter, and Escape for suggestion navigation.
|
|
134
|
+
*/
|
|
135
|
+
const onInputKeyDown = useCallback((event) => {
|
|
136
|
+
if (!source || !open) {
|
|
137
|
+
return false;
|
|
138
|
+
}
|
|
139
|
+
if (event.key === 'ArrowDown') {
|
|
140
|
+
event.preventDefault();
|
|
141
|
+
if (items.length === 0) {
|
|
142
|
+
return true;
|
|
143
|
+
}
|
|
144
|
+
setActiveIndex((index) => (index + 1) % items.length);
|
|
145
|
+
return true;
|
|
146
|
+
}
|
|
147
|
+
if (event.key === 'ArrowUp') {
|
|
148
|
+
event.preventDefault();
|
|
149
|
+
if (items.length === 0) {
|
|
150
|
+
return true;
|
|
151
|
+
}
|
|
152
|
+
setActiveIndex((index) => (index <= 0 ? items.length - 1 : index - 1));
|
|
153
|
+
return true;
|
|
154
|
+
}
|
|
155
|
+
if (event.key === 'Enter') {
|
|
156
|
+
if (activeIndex >= 0 && items[activeIndex]) {
|
|
157
|
+
event.preventDefault();
|
|
158
|
+
selectItem(items[activeIndex]);
|
|
159
|
+
return true;
|
|
160
|
+
}
|
|
161
|
+
void commit();
|
|
162
|
+
closeSuggestions();
|
|
163
|
+
return false;
|
|
164
|
+
}
|
|
165
|
+
if (event.key === 'Escape') {
|
|
166
|
+
event.preventDefault();
|
|
167
|
+
closeSuggestions();
|
|
168
|
+
return true;
|
|
169
|
+
}
|
|
170
|
+
return false;
|
|
171
|
+
}, [activeIndex, closeSuggestions, commit, items, open, selectItem, source]);
|
|
172
|
+
useEffect(() => {
|
|
173
|
+
if (open) {
|
|
174
|
+
refreshItems();
|
|
175
|
+
}
|
|
176
|
+
}, [open, refreshItems, value]);
|
|
177
|
+
return {
|
|
178
|
+
open,
|
|
179
|
+
items,
|
|
180
|
+
activeIndex,
|
|
181
|
+
anchorRef,
|
|
182
|
+
listboxId,
|
|
183
|
+
onFocus,
|
|
184
|
+
onBlur,
|
|
185
|
+
onInputKeyDown,
|
|
186
|
+
selectItem,
|
|
187
|
+
refreshItems,
|
|
188
|
+
setActiveIndex,
|
|
189
|
+
closeSuggestions
|
|
190
|
+
};
|
|
191
|
+
}
|
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"index.d.ts","sourceRoot":"","sources":["../../../src/components/Button/index.tsx"],"names":[],"mappings":"AAAA,OAAO,KAAK,EAAE,oBAAoB,EAAE,GAAG,EAAE,SAAS,EAAE,MAAM,OAAO,CAAC;AAElE;;GAEG;AACH,MAAM,MAAM,aAAa,GACrB,SAAS,GACT,WAAW,GACX,eAAe,GACf,iBAAiB,GACjB,SAAS,GACT,MAAM,GACN,YAAY,CAAC;AAEjB,KAAK,iBAAiB,GAAG,MAAM,GAAG,YAAY,CAAC;AAE/C,KAAK,cAAc,GACf;IAAE,YAAY,EAAE,MAAM,CAAC;IAAC,iBAAiB,CAAC,EAAE,SAAS,CAAA;CAAE,GACvD;IAAE,iBAAiB,EAAE,MAAM,CAAC;IAAC,YAAY,CAAC,EAAE,SAAS,CAAA;CAAE,CAAC;AAE5D,KAAK,SAAS,GAAG,IAAI,CAAC,oBAAoB,CAAC,iBAAiB,CAAC,EAAE,YAAY,GAAG,iBAAiB,CAAC,GAAG;IACjG;;OAEG;IACH,SAAS,CAAC,EAAE,MAAM,CAAC;IAEnB;;OAEG;IACH,QAAQ,CAAC,EAAE,SAAS,CAAC,iBAAiB,GAAG,IAAI,CAAC,CAAC;CAChD,CAAC;AAEF,MAAM,MAAM,WAAW,GACnB,CAAC,SAAS,GAAG;IAAE,OAAO,EAAE,iBAAiB,CAAA;CAAE,GAAG,cAAc,CAAC,GAC7D,CAAC,SAAS,GAAG;IAAE,OAAO,CAAC,EAAE,OAAO,CAAC,aAAa,EAAE,iBAAiB,CAAC,CAAA;CAAE,CAAC,CAAC;
|
|
1
|
+
{"version":3,"file":"index.d.ts","sourceRoot":"","sources":["../../../src/components/Button/index.tsx"],"names":[],"mappings":"AAAA,OAAO,KAAK,EAAE,oBAAoB,EAAE,GAAG,EAAE,SAAS,EAAE,MAAM,OAAO,CAAC;AAElE;;GAEG;AACH,MAAM,MAAM,aAAa,GACrB,SAAS,GACT,WAAW,GACX,eAAe,GACf,iBAAiB,GACjB,SAAS,GACT,MAAM,GACN,YAAY,CAAC;AAEjB,KAAK,iBAAiB,GAAG,MAAM,GAAG,YAAY,CAAC;AAE/C,KAAK,cAAc,GACf;IAAE,YAAY,EAAE,MAAM,CAAC;IAAC,iBAAiB,CAAC,EAAE,SAAS,CAAA;CAAE,GACvD;IAAE,iBAAiB,EAAE,MAAM,CAAC;IAAC,YAAY,CAAC,EAAE,SAAS,CAAA;CAAE,CAAC;AAE5D,KAAK,SAAS,GAAG,IAAI,CAAC,oBAAoB,CAAC,iBAAiB,CAAC,EAAE,YAAY,GAAG,iBAAiB,CAAC,GAAG;IACjG;;OAEG;IACH,SAAS,CAAC,EAAE,MAAM,CAAC;IAEnB;;OAEG;IACH,QAAQ,CAAC,EAAE,SAAS,CAAC,iBAAiB,GAAG,IAAI,CAAC,CAAC;CAChD,CAAC;AAEF,MAAM,MAAM,WAAW,GACnB,CAAC,SAAS,GAAG;IAAE,OAAO,EAAE,iBAAiB,CAAA;CAAE,GAAG,cAAc,CAAC,GAC7D,CAAC,SAAS,GAAG;IAAE,OAAO,CAAC,EAAE,OAAO,CAAC,aAAa,EAAE,iBAAiB,CAAC,CAAA;CAAE,CAAC,CAAC;AAc1E;;;;;;;;;;;;GAYG;AACH,wBAAgB,MAAM,CAAC,EACrB,OAAmB,EACnB,SAAS,EACT,IAAe,EACf,QAAQ,EACR,GAAG,KAAK,EACT,EAAE,WAAW,GAAG,GAAG,CAAC,OAAO,CAG3B"}
|
|
@@ -1,12 +1,13 @@
|
|
|
1
1
|
import { jsx as _jsx } from "@harborclient/sdk/jsx-runtime";
|
|
2
|
+
const BUTTON_BASE = 'inline-flex cursor-pointer items-center rounded-md app-no-drag';
|
|
2
3
|
const VARIANT_CLASSES = {
|
|
3
|
-
primary:
|
|
4
|
-
secondary:
|
|
5
|
-
primaryDanger:
|
|
6
|
-
secondaryDanger:
|
|
7
|
-
toolbar:
|
|
8
|
-
icon:
|
|
9
|
-
iconDanger:
|
|
4
|
+
primary: `${BUTTON_BASE} min-h-[32px] justify-center border border-transparent bg-accent px-3 py-1 text-[15px] font-medium text-white shadow-sm hover:brightness-110 disabled:cursor-not-allowed disabled:opacity-50`,
|
|
5
|
+
secondary: `${BUTTON_BASE} min-h-[32px] justify-center border border-separator bg-control px-3 py-1 text-[15px] text-text shadow-sm hover:bg-selection disabled:cursor-not-allowed disabled:opacity-50`,
|
|
6
|
+
primaryDanger: `${BUTTON_BASE} min-h-[32px] justify-center border border-transparent bg-danger px-3 py-1 text-[15px] font-medium text-white shadow-sm hover:brightness-110 disabled:cursor-not-allowed disabled:opacity-50`,
|
|
7
|
+
secondaryDanger: `${BUTTON_BASE} min-h-[32px] justify-center border border-separator bg-control px-3 py-1 text-[15px] text-danger shadow-sm hover:bg-danger/15 disabled:cursor-not-allowed disabled:opacity-50`,
|
|
8
|
+
toolbar: `${BUTTON_BASE} min-h-[32px] border-none bg-transparent px-2 py-1 text-[15px] hover:bg-selection`,
|
|
9
|
+
icon: `${BUTTON_BASE} size-[30px] shrink-0 justify-center border-none bg-transparent text-muted hover:bg-selection hover:text-text`,
|
|
10
|
+
iconDanger: `${BUTTON_BASE} size-[30px] shrink-0 justify-center border-none bg-transparent text-muted hover:bg-danger/15 hover:text-danger`
|
|
10
11
|
};
|
|
11
12
|
/**
|
|
12
13
|
* macOS-style button with shared variant presets for primary actions, secondary
|
|
@@ -1,5 +1,6 @@
|
|
|
1
1
|
import type { JSX } from 'react';
|
|
2
2
|
import type { KeyValue, Variable } from '../../types.js';
|
|
3
|
+
import type { AutocompleteSource } from '../Autocomplete/types.js';
|
|
3
4
|
export interface Props {
|
|
4
5
|
/**
|
|
5
6
|
* Editable key-value rows.
|
|
@@ -27,9 +28,17 @@ export interface Props {
|
|
|
27
28
|
* Opens collection settings to edit a hovered variable.
|
|
28
29
|
*/
|
|
29
30
|
onEditVariable?: () => void;
|
|
31
|
+
/**
|
|
32
|
+
* Optional async source for key column autocomplete suggestions.
|
|
33
|
+
*/
|
|
34
|
+
keySource?: AutocompleteSource;
|
|
35
|
+
/**
|
|
36
|
+
* Optional async source for value column autocomplete suggestions.
|
|
37
|
+
*/
|
|
38
|
+
valueSource?: AutocompleteSource;
|
|
30
39
|
}
|
|
31
40
|
/**
|
|
32
41
|
* Editable table of key-value rows with enable toggles for headers and params.
|
|
33
42
|
*/
|
|
34
|
-
export declare function KeyValueEditor({ rows, onChange, placeholderKey, placeholderValue, variables, onEditVariable }: Props): JSX.Element;
|
|
43
|
+
export declare function KeyValueEditor({ rows, onChange, placeholderKey, placeholderValue, variables, onEditVariable, keySource, valueSource }: Props): JSX.Element;
|
|
35
44
|
//# sourceMappingURL=index.d.ts.map
|
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"index.d.ts","sourceRoot":"","sources":["../../../src/components/KeyValueEditor/index.tsx"],"names":[],"mappings":"AACA,OAAO,KAAK,EAAE,GAAG,EAAE,MAAM,OAAO,CAAC;AACjC,OAAO,KAAK,EAAE,QAAQ,EAAE,QAAQ,EAAE,MAAM,gBAAgB,CAAC;
|
|
1
|
+
{"version":3,"file":"index.d.ts","sourceRoot":"","sources":["../../../src/components/KeyValueEditor/index.tsx"],"names":[],"mappings":"AACA,OAAO,KAAK,EAAE,GAAG,EAAE,MAAM,OAAO,CAAC;AACjC,OAAO,KAAK,EAAE,QAAQ,EAAE,QAAQ,EAAE,MAAM,gBAAgB,CAAC;AAEzD,OAAO,KAAK,EAAE,kBAAkB,EAAE,MAAM,0BAA0B,CAAC;AAOnE,MAAM,WAAW,KAAK;IACpB;;OAEG;IACH,IAAI,EAAE,QAAQ,EAAE,CAAC;IAEjB;;;;OAIG;IACH,QAAQ,EAAE,CAAC,IAAI,EAAE,QAAQ,EAAE,KAAK,IAAI,CAAC;IAErC;;OAEG;IACH,cAAc,CAAC,EAAE,MAAM,CAAC;IAExB;;OAEG;IACH,gBAAgB,CAAC,EAAE,MAAM,CAAC;IAE1B;;OAEG;IACH,SAAS,EAAE,QAAQ,EAAE,CAAC;IAEtB;;OAEG;IACH,cAAc,CAAC,EAAE,MAAM,IAAI,CAAC;IAE5B;;OAEG;IACH,SAAS,CAAC,EAAE,kBAAkB,CAAC;IAE/B;;OAEG;IACH,WAAW,CAAC,EAAE,kBAAkB,CAAC;CAClC;AAED;;GAEG;AACH,wBAAgB,cAAc,CAAC,EAC7B,IAAI,EACJ,QAAQ,EACR,cAAsB,EACtB,gBAA0B,EAC1B,SAAS,EACT,cAAc,EACd,SAAS,EACT,WAAW,EACZ,EAAE,KAAK,GAAG,GAAG,CAAC,OAAO,CA6FrB"}
|
|
@@ -1,14 +1,15 @@
|
|
|
1
1
|
import { jsx as _jsx, jsxs as _jsxs } from "@harborclient/sdk/jsx-runtime";
|
|
2
2
|
import { faXmark } from '@fortawesome/free-solid-svg-icons';
|
|
3
|
+
import { AutocompleteInput } from '../Autocomplete/index.js';
|
|
3
4
|
import { Button } from '../Button/index.js';
|
|
4
5
|
import { FaIcon } from '../FaIcon/index.js';
|
|
5
|
-
import { Checkbox,
|
|
6
|
+
import { Checkbox, fieldFrame } from '../forms/index.js';
|
|
6
7
|
import { Table, TableBody, TableCell, TableHead, TableHeader } from '../Table/index.js';
|
|
7
8
|
import { VariableInput } from '../VariableInput/index.js';
|
|
8
9
|
/**
|
|
9
10
|
* Editable table of key-value rows with enable toggles for headers and params.
|
|
10
11
|
*/
|
|
11
|
-
export function KeyValueEditor({ rows, onChange, placeholderKey = 'Key', placeholderValue = 'Value', variables, onEditVariable }) {
|
|
12
|
+
export function KeyValueEditor({ rows, onChange, placeholderKey = 'Key', placeholderValue = 'Value', variables, onEditVariable, keySource, valueSource }) {
|
|
12
13
|
/**
|
|
13
14
|
* Updates a single row by index.
|
|
14
15
|
*
|
|
@@ -35,5 +36,5 @@ export function KeyValueEditor({ rows, onChange, placeholderKey = 'Key', placeho
|
|
|
35
36
|
}
|
|
36
37
|
onChange(rows.filter((_, i) => i !== index));
|
|
37
38
|
};
|
|
38
|
-
return (_jsxs(Table, { children: [_jsx(TableHeader, { children: _jsxs("tr", { children: [_jsx(TableHead, { className: "w-6 p-0", children: _jsx("span", { className: "sr-only", children: "Enable" }) }), _jsx(TableHead, { children: "Key" }), _jsx(TableHead, { children: "Value" }), _jsx(TableHead, { className: "w-7 p-0" })] }) }), _jsx(TableBody, { children: rows.map((row, index) => (_jsxs("tr", { children: [_jsx(TableCell, { className: "w-6 p-1 text-center", children: _jsx(Checkbox, { className: "app-no-drag", checked: row.enabled, onChange: (e) => updateRow(index, { enabled: e.target.checked }), "aria-label": `Enable row ${index + 1}`, title: "Enable" }) }), _jsx(TableCell, { children: _jsx(
|
|
39
|
+
return (_jsxs(Table, { children: [_jsx(TableHeader, { children: _jsxs("tr", { children: [_jsx(TableHead, { className: "w-6 p-0", children: _jsx("span", { className: "sr-only", children: "Enable" }) }), _jsx(TableHead, { children: "Key" }), _jsx(TableHead, { children: "Value" }), _jsx(TableHead, { className: "w-7 p-0" })] }) }), _jsx(TableBody, { children: rows.map((row, index) => (_jsxs("tr", { children: [_jsx(TableCell, { className: "w-6 p-1 text-center", children: _jsx(Checkbox, { className: "app-no-drag", checked: row.enabled, onChange: (e) => updateRow(index, { enabled: e.target.checked }), "aria-label": `Enable row ${index + 1}`, title: "Enable" }) }), _jsx(TableCell, { children: _jsx(AutocompleteInput, { type: "text", className: "w-full", value: row.key, source: keySource, placeholder: placeholderKey, "aria-label": `Key, row ${index + 1}`, onChange: (key) => updateRow(index, { key }) }) }), _jsx(TableCell, { children: _jsx(VariableInput, { wrapperClassName: `${fieldFrame} w-full`, className: "app-no-drag", value: row.value, onChange: (value) => updateRow(index, { value }), variables: variables, source: valueSource, placeholder: placeholderValue, "aria-label": `Value, row ${index + 1}`, onEditVariable: onEditVariable }) }), _jsx(TableCell, { className: "w-7 p-1 text-center", children: _jsx(Button, { type: "button", variant: "iconDanger", onClick: () => removeRow(index), title: "Remove", "aria-label": `Remove row ${index + 1}`, children: _jsx(FaIcon, { icon: faXmark, className: "h-3.5 w-3.5" }) }) })] }, index))) })] }));
|
|
39
40
|
}
|