@harborclient/sdk 1.1.12 → 1.1.14
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/components/Badge/index.d.ts +1 -1
- package/dist/components/Badge/index.d.ts.map +1 -1
- package/dist/components/Badge/index.js +2 -0
- package/dist/components/CatalogCard/index.d.ts +51 -0
- package/dist/components/CatalogCard/index.d.ts.map +1 -0
- package/dist/components/CatalogCard/index.js +23 -0
- package/dist/components/CatalogReadmeMarkdown/index.d.ts +13 -0
- package/dist/components/CatalogReadmeMarkdown/index.d.ts.map +1 -0
- package/dist/components/CatalogReadmeMarkdown/index.js +53 -0
- package/dist/components/FormGroup/index.d.ts +6 -1
- package/dist/components/FormGroup/index.d.ts.map +1 -1
- package/dist/components/FormGroup/index.js +21 -10
- package/dist/components/FormSection/index.d.ts +37 -0
- package/dist/components/FormSection/index.d.ts.map +1 -0
- package/dist/components/FormSection/index.js +9 -0
- package/dist/components/ProgressBar/index.d.ts +20 -0
- package/dist/components/ProgressBar/index.d.ts.map +1 -0
- package/dist/components/ProgressBar/index.js +10 -0
- package/dist/components/ProgressBar/progressBar.logic.d.ts +9 -0
- package/dist/components/ProgressBar/progressBar.logic.d.ts.map +1 -0
- package/dist/components/ProgressBar/progressBar.logic.js +13 -0
- package/dist/components/PromptModal/index.d.ts +82 -0
- package/dist/components/PromptModal/index.d.ts.map +1 -0
- package/dist/components/PromptModal/index.js +22 -0
- package/dist/components/PromptModal/promptModal.logic.d.ts +8 -0
- package/dist/components/PromptModal/promptModal.logic.d.ts.map +1 -0
- package/dist/components/PromptModal/promptModal.logic.js +9 -0
- package/dist/components/ScreenshotCarousel/ScreenshotLightbox.d.ts +29 -0
- package/dist/components/ScreenshotCarousel/ScreenshotLightbox.d.ts.map +1 -0
- package/dist/components/ScreenshotCarousel/ScreenshotLightbox.js +66 -0
- package/dist/components/ScreenshotCarousel/index.d.ts +35 -0
- package/dist/components/ScreenshotCarousel/index.d.ts.map +1 -0
- package/dist/components/ScreenshotCarousel/index.js +89 -0
- package/dist/components/ScreenshotCarousel/variants.d.ts +17 -0
- package/dist/components/ScreenshotCarousel/variants.d.ts.map +1 -0
- package/dist/components/ScreenshotCarousel/variants.js +22 -0
- package/dist/components/SelectionActionToolbar/index.d.ts +41 -0
- package/dist/components/SelectionActionToolbar/index.d.ts.map +1 -0
- package/dist/components/SelectionActionToolbar/index.js +13 -0
- package/dist/components/SettingIdLabel/index.d.ts +16 -0
- package/dist/components/SettingIdLabel/index.d.ts.map +1 -0
- package/dist/components/SettingIdLabel/index.js +7 -0
- package/dist/components/SettingSectionHeading/index.d.ts +33 -0
- package/dist/components/SettingSectionHeading/index.d.ts.map +1 -0
- package/dist/components/SettingSectionHeading/index.js +10 -0
- package/dist/components/SidebarItem/SidebarBadge.d.ts +49 -0
- package/dist/components/SidebarItem/SidebarBadge.d.ts.map +1 -0
- package/dist/components/SidebarItem/SidebarBadge.js +52 -0
- package/dist/components/SidebarItem/SidebarRunItem.d.ts.map +1 -1
- package/dist/components/SidebarItem/SidebarRunItem.js +2 -1
- package/dist/components/SidebarItem/index.d.ts +2 -1
- package/dist/components/SidebarItem/index.d.ts.map +1 -1
- package/dist/components/SidebarItem/index.js +2 -1
- package/dist/components/SidebarItem/sidebarItemClasses.d.ts +8 -0
- package/dist/components/SidebarItem/sidebarItemClasses.d.ts.map +1 -1
- package/dist/components/SidebarItem/sidebarItemClasses.js +18 -8
- package/dist/components/StatusDot/index.d.ts +42 -0
- package/dist/components/StatusDot/index.d.ts.map +1 -0
- package/dist/components/StatusDot/index.js +42 -0
- package/dist/components/ThemeVariantPickerModal/index.d.ts +71 -0
- package/dist/components/ThemeVariantPickerModal/index.d.ts.map +1 -0
- package/dist/components/ThemeVariantPickerModal/index.js +37 -0
- package/dist/components/index.d.ts +24 -1
- package/dist/components/index.d.ts.map +1 -1
- package/dist/components/index.js +15 -1
- package/package.json +6 -2
|
@@ -2,7 +2,7 @@ import type { ComponentPropsWithoutRef, JSX, ReactNode } from 'react';
|
|
|
2
2
|
/**
|
|
3
3
|
* Visual tone for compact status badges.
|
|
4
4
|
*/
|
|
5
|
-
export type BadgeVariant = 'success' | 'danger' | 'muted' | 'accent' | 'warning';
|
|
5
|
+
export type BadgeVariant = 'success' | 'danger' | 'muted' | 'accent' | 'warning' | 'category';
|
|
6
6
|
interface Props extends Omit<ComponentPropsWithoutRef<'span'>, 'children'> {
|
|
7
7
|
/**
|
|
8
8
|
* Badge label content.
|
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"index.d.ts","sourceRoot":"","sources":["../../../src/components/Badge/index.tsx"],"names":[],"mappings":"AAAA,OAAO,KAAK,EAAE,wBAAwB,EAAE,GAAG,EAAE,SAAS,EAAE,MAAM,OAAO,CAAC;AAGtE;;GAEG;AACH,MAAM,MAAM,YAAY,GAAG,SAAS,GAAG,QAAQ,GAAG,OAAO,GAAG,QAAQ,GAAG,SAAS,CAAC;
|
|
1
|
+
{"version":3,"file":"index.d.ts","sourceRoot":"","sources":["../../../src/components/Badge/index.tsx"],"names":[],"mappings":"AAAA,OAAO,KAAK,EAAE,wBAAwB,EAAE,GAAG,EAAE,SAAS,EAAE,MAAM,OAAO,CAAC;AAGtE;;GAEG;AACH,MAAM,MAAM,YAAY,GAAG,SAAS,GAAG,QAAQ,GAAG,OAAO,GAAG,QAAQ,GAAG,SAAS,GAAG,UAAU,CAAC;AAE9F,UAAU,KAAM,SAAQ,IAAI,CAAC,wBAAwB,CAAC,MAAM,CAAC,EAAE,UAAU,CAAC;IACxE;;OAEG;IACH,QAAQ,EAAE,SAAS,CAAC;IAEpB;;OAEG;IACH,OAAO,CAAC,EAAE,YAAY,CAAC;CACxB;AAyBD;;GAEG;AACH,wBAAgB,KAAK,CAAC,EAAE,QAAQ,EAAE,OAAiB,EAAE,SAAS,EAAE,GAAG,KAAK,EAAE,EAAE,KAAK,GAAG,GAAG,CAAC,OAAO,CAa9F"}
|
|
@@ -0,0 +1,51 @@
|
|
|
1
|
+
import type { JSX, ReactNode } from 'react';
|
|
2
|
+
/**
|
|
3
|
+
* One category chip shown on a marketplace catalog card.
|
|
4
|
+
*/
|
|
5
|
+
export interface CatalogCardCategory {
|
|
6
|
+
/**
|
|
7
|
+
* Stable category id used as the chip key.
|
|
8
|
+
*/
|
|
9
|
+
id: string;
|
|
10
|
+
/**
|
|
11
|
+
* Human-readable label rendered inside the chip.
|
|
12
|
+
*/
|
|
13
|
+
label: string;
|
|
14
|
+
}
|
|
15
|
+
export interface Props {
|
|
16
|
+
/**
|
|
17
|
+
* Marketplace listing display name.
|
|
18
|
+
*/
|
|
19
|
+
name: string;
|
|
20
|
+
/**
|
|
21
|
+
* Published version string shown beside the name.
|
|
22
|
+
*/
|
|
23
|
+
version: string;
|
|
24
|
+
/**
|
|
25
|
+
* Short summary text clamped to three lines.
|
|
26
|
+
*/
|
|
27
|
+
summary: string;
|
|
28
|
+
/**
|
|
29
|
+
* Opens the catalog detail view for this listing.
|
|
30
|
+
*/
|
|
31
|
+
onOpen: () => void;
|
|
32
|
+
/**
|
|
33
|
+
* Optional preview slot, typically a screenshot carousel.
|
|
34
|
+
* When omitted, a "No preview" placeholder is rendered.
|
|
35
|
+
*/
|
|
36
|
+
preview?: ReactNode;
|
|
37
|
+
/**
|
|
38
|
+
* Category chips rendered below the summary.
|
|
39
|
+
* Omit or pass an empty array to hide the chip row.
|
|
40
|
+
*/
|
|
41
|
+
categories?: CatalogCardCategory[];
|
|
42
|
+
/**
|
|
43
|
+
* Optional footer slot for action buttons or status rows.
|
|
44
|
+
*/
|
|
45
|
+
footer?: ReactNode;
|
|
46
|
+
}
|
|
47
|
+
/**
|
|
48
|
+
* Compact marketplace preview card; opens the detail view on activation.
|
|
49
|
+
*/
|
|
50
|
+
export declare function CatalogCard({ name, version, summary, onOpen, preview, categories, footer }: Props): JSX.Element;
|
|
51
|
+
//# sourceMappingURL=index.d.ts.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"index.d.ts","sourceRoot":"","sources":["../../../src/components/CatalogCard/index.tsx"],"names":[],"mappings":"AAAA,OAAO,KAAK,EAAE,GAAG,EAAiB,SAAS,EAAE,MAAM,OAAO,CAAC;AAK3D;;GAEG;AACH,MAAM,WAAW,mBAAmB;IAClC;;OAEG;IACH,EAAE,EAAE,MAAM,CAAC;IAEX;;OAEG;IACH,KAAK,EAAE,MAAM,CAAC;CACf;AAED,MAAM,WAAW,KAAK;IACpB;;OAEG;IACH,IAAI,EAAE,MAAM,CAAC;IAEb;;OAEG;IACH,OAAO,EAAE,MAAM,CAAC;IAEhB;;OAEG;IACH,OAAO,EAAE,MAAM,CAAC;IAEhB;;OAEG;IACH,MAAM,EAAE,MAAM,IAAI,CAAC;IAEnB;;;OAGG;IACH,OAAO,CAAC,EAAE,SAAS,CAAC;IAEpB;;;OAGG;IACH,UAAU,CAAC,EAAE,mBAAmB,EAAE,CAAC;IAEnC;;OAEG;IACH,MAAM,CAAC,EAAE,SAAS,CAAC;CACpB;AAeD;;GAEG;AACH,wBAAgB,WAAW,CAAC,EAC1B,IAAI,EACJ,OAAO,EACP,OAAO,EACP,MAAM,EACN,OAAO,EACP,UAAU,EACV,MAAM,EACP,EAAE,KAAK,GAAG,GAAG,CAAC,OAAO,CAyCrB"}
|
|
@@ -0,0 +1,23 @@
|
|
|
1
|
+
import { jsx as _jsx, jsxs as _jsxs } from "@harborclient/sdk/jsx-runtime";
|
|
2
|
+
import { Badge } from '../Badge/index.js';
|
|
3
|
+
import { Card } from '../Card/index.js';
|
|
4
|
+
import { cn } from '../utils.js';
|
|
5
|
+
/**
|
|
6
|
+
* Opens the detail view when the card is activated from the keyboard.
|
|
7
|
+
*
|
|
8
|
+
* @param event - Keyboard event on the card list item.
|
|
9
|
+
* @param onOpen - Handler that opens the catalog detail view.
|
|
10
|
+
*/
|
|
11
|
+
function handleKeyDown(event, onOpen) {
|
|
12
|
+
if (event.key === 'Enter' || event.key === ' ') {
|
|
13
|
+
event.preventDefault();
|
|
14
|
+
onOpen();
|
|
15
|
+
}
|
|
16
|
+
}
|
|
17
|
+
/**
|
|
18
|
+
* Compact marketplace preview card; opens the detail view on activation.
|
|
19
|
+
*/
|
|
20
|
+
export function CatalogCard({ name, version, summary, onOpen, preview, categories, footer }) {
|
|
21
|
+
const showCategories = categories != null && categories.length > 0;
|
|
22
|
+
return (_jsx("li", { tabIndex: 0, "aria-label": `View details for ${name}`, onClick: onOpen, onKeyDown: (event) => handleKeyDown(event, onOpen), children: _jsxs(Card, { className: "h-full cursor-pointer flex-col overflow-hidden hover:bg-selection/40", children: [preview ?? (_jsx("div", { className: "bg-panel flex aspect-video w-full items-center justify-center border-b border-separator text-[14px] text-muted", "aria-hidden": true, children: "No preview" })), _jsxs(Card.Body, { className: "flex flex-1 flex-col gap-1.5 p-3", children: [_jsxs("div", { className: "flex items-baseline justify-between gap-2", children: [_jsx("h3", { className: "m-0 min-w-0 truncate text-[14px] font-semibold text-text", children: name }), _jsx("span", { className: "shrink-0 text-[14px] text-muted", children: version })] }), _jsx("p", { className: "m-0 line-clamp-3 text-[14px] text-text", children: summary }), showCategories ? (_jsx("div", { className: "mt-auto flex flex-wrap gap-1.5 pt-1.5", children: categories.map((category) => (_jsx(Badge, { variant: "category", className: "px-2", children: category.label }, category.id))) })) : null] }), footer != null ? _jsx("div", { className: cn('border-t border-separator'), children: footer }) : null] }) }));
|
|
23
|
+
}
|
|
@@ -0,0 +1,13 @@
|
|
|
1
|
+
import type { JSX } from 'react';
|
|
2
|
+
interface Props {
|
|
3
|
+
/**
|
|
4
|
+
* Raw markdown string from a catalog README or description file.
|
|
5
|
+
*/
|
|
6
|
+
content: string;
|
|
7
|
+
}
|
|
8
|
+
/**
|
|
9
|
+
* Renders catalog README markdown with GFM support and GitHub-like spacing.
|
|
10
|
+
*/
|
|
11
|
+
export declare function CatalogReadmeMarkdown({ content }: Props): JSX.Element;
|
|
12
|
+
export {};
|
|
13
|
+
//# sourceMappingURL=index.d.ts.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"index.d.ts","sourceRoot":"","sources":["../../../src/components/CatalogReadmeMarkdown/index.tsx"],"names":[],"mappings":"AAAA,OAAO,KAAK,EAAE,GAAG,EAAE,MAAM,OAAO,CAAC;AAIjC,UAAU,KAAK;IACb;;OAEG;IACH,OAAO,EAAE,MAAM,CAAC;CACjB;AAyGD;;GAEG;AACH,wBAAgB,qBAAqB,CAAC,EAAE,OAAO,EAAE,EAAE,KAAK,GAAG,GAAG,CAAC,OAAO,CAUrE"}
|
|
@@ -0,0 +1,53 @@
|
|
|
1
|
+
import { jsx as _jsx } from "@harborclient/sdk/jsx-runtime";
|
|
2
|
+
import ReactMarkdown from 'react-markdown';
|
|
3
|
+
import remarkGfm from 'remark-gfm';
|
|
4
|
+
/**
|
|
5
|
+
* Builds react-markdown component overrides styled like a GitHub README.
|
|
6
|
+
*
|
|
7
|
+
* Uses explicit element classes instead of Tailwind Typography so spacing and
|
|
8
|
+
* font sizes stay predictable within HarborClient theme tokens.
|
|
9
|
+
*
|
|
10
|
+
* @returns Component map for {@link ReactMarkdown}.
|
|
11
|
+
*/
|
|
12
|
+
function createReadmeMarkdownComponents() {
|
|
13
|
+
return {
|
|
14
|
+
p: ({ children }) => _jsx("p", { className: "mb-4 break-words last:mb-0", children: children }),
|
|
15
|
+
a: ({ href, children }) => (_jsx("a", { href: href, target: "_blank", rel: "noopener noreferrer", className: "text-accent underline underline-offset-2 hover:opacity-90", children: children })),
|
|
16
|
+
ul: ({ children }) => (_jsx("ul", { className: "my-4 list-disc space-y-2 pl-6 last:mb-0 [&>li]:break-words", children: children })),
|
|
17
|
+
ol: ({ children }) => (_jsx("ol", { className: "my-4 list-decimal space-y-2 pl-6 last:mb-0 [&>li]:break-words", children: children })),
|
|
18
|
+
li: ({ children }) => (_jsx("li", { className: "break-words [&>p]:mb-2 [&>p:last-child]:mb-0", children: children })),
|
|
19
|
+
blockquote: ({ children }) => (_jsx("blockquote", { className: "my-4 border-l-4 border-separator pl-4 text-muted [&>p:last-child]:mb-0", children: children })),
|
|
20
|
+
hr: () => _jsx("hr", { className: "my-6 border-separator" }),
|
|
21
|
+
h1: ({ children }) => (_jsx("h1", { className: "mt-6 mb-4 border-b border-separator pb-2 text-[20px] font-semibold first:mt-0", children: children })),
|
|
22
|
+
h2: ({ children }) => (_jsx("h2", { className: "mt-6 mb-3 border-b border-separator pb-2 text-[18px] font-semibold first:mt-0", children: children })),
|
|
23
|
+
h3: ({ children }) => _jsx("h3", { className: "mt-5 mb-3 font-semibold first:mt-0", children: children }),
|
|
24
|
+
h4: ({ children }) => (_jsx("h4", { className: "mt-4 mb-2 text-[14px] font-semibold first:mt-0", children: children })),
|
|
25
|
+
h5: ({ children }) => (_jsx("h5", { className: "mt-4 mb-2 text-[14px] font-semibold first:mt-0", children: children })),
|
|
26
|
+
h6: ({ children }) => (_jsx("h6", { className: "mt-4 mb-2 text-[14px] font-semibold first:mt-0", children: children })),
|
|
27
|
+
pre: ({ children }) => (_jsx("pre", { className: "my-4 overflow-x-auto rounded-md border border-separator bg-sidebar p-4 font-mono text-[14px]", children: children })),
|
|
28
|
+
code: ({ className, children }) => {
|
|
29
|
+
const isBlock = typeof className === 'string' && className.includes('language-');
|
|
30
|
+
if (isBlock) {
|
|
31
|
+
return (_jsx("code", { className: `font-mono text-[14px] ${className ?? ''}`.trim(), children: children }));
|
|
32
|
+
}
|
|
33
|
+
return (_jsx("code", { className: "rounded bg-sidebar px-1.5 py-0.5 font-mono text-[14px]", children: children }));
|
|
34
|
+
},
|
|
35
|
+
table: ({ children }) => (_jsx("div", { className: "my-4 overflow-x-auto last:mb-0", children: _jsx("table", { className: "w-full border-collapse text-left text-[14px]", children: children }) })),
|
|
36
|
+
thead: ({ children }) => _jsx("thead", { children: children }),
|
|
37
|
+
tbody: ({ children }) => _jsx("tbody", { children: children }),
|
|
38
|
+
tr: ({ children }) => _jsx("tr", { children: children }),
|
|
39
|
+
th: ({ children }) => (_jsx("th", { className: "border border-separator bg-sidebar/40 px-2 py-1 align-top font-semibold", children: children })),
|
|
40
|
+
td: ({ children }) => (_jsx("td", { className: "border border-separator px-2 py-1 align-top", children: children })),
|
|
41
|
+
img: ({ src, alt }) => (_jsx("img", { src: src, alt: alt ?? '', className: "my-4 max-w-full rounded-md border border-separator" })),
|
|
42
|
+
strong: ({ children }) => _jsx("strong", { className: "font-semibold", children: children }),
|
|
43
|
+
em: ({ children }) => _jsx("em", { className: "italic", children: children }),
|
|
44
|
+
del: ({ children }) => _jsx("del", { className: "opacity-80", children: children })
|
|
45
|
+
};
|
|
46
|
+
}
|
|
47
|
+
/**
|
|
48
|
+
* Renders catalog README markdown with GFM support and GitHub-like spacing.
|
|
49
|
+
*/
|
|
50
|
+
export function CatalogReadmeMarkdown({ content }) {
|
|
51
|
+
const components = createReadmeMarkdownComponents();
|
|
52
|
+
return (_jsx("div", { className: "leading-relaxed break-words text-text [&>*:first-child]:mt-0 [&>*:last-child]:mb-0", children: _jsx(ReactMarkdown, { remarkPlugins: [remarkGfm], components: components, children: content }) }));
|
|
53
|
+
}
|
|
@@ -57,12 +57,17 @@ interface Props extends Omit<ComponentPropsWithoutRef<'div'>, 'children' | 'clas
|
|
|
57
57
|
* Extra classes on the label element (associated and checkboxAdjacent layouts).
|
|
58
58
|
*/
|
|
59
59
|
labelClassName?: string;
|
|
60
|
+
/**
|
|
61
|
+
* When false, omits the default border and padding on stacked, checkbox, and
|
|
62
|
+
* inline layouts for fields nested inside an already-bordered section.
|
|
63
|
+
*/
|
|
64
|
+
bordered?: boolean;
|
|
60
65
|
}
|
|
61
66
|
/**
|
|
62
67
|
* Reusable form field wrapper that pairs a label with one or more controls.
|
|
63
68
|
* Supports stacked fields, checkboxes, inline rows, radio options, and
|
|
64
69
|
* adjacent checkbox rows used in list pickers.
|
|
65
70
|
*/
|
|
66
|
-
export declare function FormGroup({ label, children, htmlFor, description, error, errorId, descriptionId, layout, labelTone, srOnly, className, labelClassName, ...props }: Props): JSX.Element;
|
|
71
|
+
export declare function FormGroup({ label, children, htmlFor, description, error, errorId, descriptionId, layout, labelTone, srOnly, className, labelClassName, bordered, ...props }: Props): JSX.Element;
|
|
67
72
|
export {};
|
|
68
73
|
//# sourceMappingURL=index.d.ts.map
|
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"index.d.ts","sourceRoot":"","sources":["../../../src/components/FormGroup/index.tsx"],"names":[],"mappings":"AACA,OAAO,KAAK,EAAE,wBAAwB,EAAE,GAAG,EAAE,SAAS,EAAE,MAAM,OAAO,CAAC;AAItE;;GAEG;AACH,MAAM,MAAM,eAAe,GACvB,SAAS,GACT,UAAU,GACV,QAAQ,GACR,OAAO,GACP,kBAAkB,GAClB,YAAY,CAAC;AAEjB;;GAEG;AACH,MAAM,MAAM,kBAAkB,GAAG,SAAS,GAAG,OAAO,CAAC;AAErD,UAAU,KAAM,SAAQ,IAAI,CAAC,wBAAwB,CAAC,KAAK,CAAC,EAAE,UAAU,GAAG,WAAW,CAAC;IACrF;;OAEG;IACH,KAAK,EAAE,SAAS,CAAC;IAEjB;;OAEG;IACH,QAAQ,CAAC,EAAE,SAAS,CAAC;IAErB;;OAEG;IACH,OAAO,CAAC,EAAE,MAAM,CAAC;IAEjB;;;OAGG;IACH,WAAW,CAAC,EAAE,SAAS,CAAC;IAExB;;OAEG;IACH,KAAK,CAAC,EAAE,SAAS,CAAC;IAElB;;OAEG;IACH,OAAO,CAAC,EAAE,MAAM,CAAC;IAEjB;;OAEG;IACH,aAAa,CAAC,EAAE,MAAM,CAAC;IAEvB;;OAEG;IACH,MAAM,CAAC,EAAE,eAAe,CAAC;IAEzB;;OAEG;IACH,SAAS,CAAC,EAAE,kBAAkB,CAAC;IAE/B;;OAEG;IACH,MAAM,CAAC,EAAE,OAAO,CAAC;IAEjB;;OAEG;IACH,SAAS,CAAC,EAAE,MAAM,CAAC;IAEnB;;OAEG;IACH,cAAc,CAAC,EAAE,MAAM,CAAC;
|
|
1
|
+
{"version":3,"file":"index.d.ts","sourceRoot":"","sources":["../../../src/components/FormGroup/index.tsx"],"names":[],"mappings":"AACA,OAAO,KAAK,EAAE,wBAAwB,EAAE,GAAG,EAAE,SAAS,EAAE,MAAM,OAAO,CAAC;AAItE;;GAEG;AACH,MAAM,MAAM,eAAe,GACvB,SAAS,GACT,UAAU,GACV,QAAQ,GACR,OAAO,GACP,kBAAkB,GAClB,YAAY,CAAC;AAEjB;;GAEG;AACH,MAAM,MAAM,kBAAkB,GAAG,SAAS,GAAG,OAAO,CAAC;AAErD,UAAU,KAAM,SAAQ,IAAI,CAAC,wBAAwB,CAAC,KAAK,CAAC,EAAE,UAAU,GAAG,WAAW,CAAC;IACrF;;OAEG;IACH,KAAK,EAAE,SAAS,CAAC;IAEjB;;OAEG;IACH,QAAQ,CAAC,EAAE,SAAS,CAAC;IAErB;;OAEG;IACH,OAAO,CAAC,EAAE,MAAM,CAAC;IAEjB;;;OAGG;IACH,WAAW,CAAC,EAAE,SAAS,CAAC;IAExB;;OAEG;IACH,KAAK,CAAC,EAAE,SAAS,CAAC;IAElB;;OAEG;IACH,OAAO,CAAC,EAAE,MAAM,CAAC;IAEjB;;OAEG;IACH,aAAa,CAAC,EAAE,MAAM,CAAC;IAEvB;;OAEG;IACH,MAAM,CAAC,EAAE,eAAe,CAAC;IAEzB;;OAEG;IACH,SAAS,CAAC,EAAE,kBAAkB,CAAC;IAE/B;;OAEG;IACH,MAAM,CAAC,EAAE,OAAO,CAAC;IAEjB;;OAEG;IACH,SAAS,CAAC,EAAE,MAAM,CAAC;IAEnB;;OAEG;IACH,cAAc,CAAC,EAAE,MAAM,CAAC;IAExB;;;OAGG;IACH,QAAQ,CAAC,EAAE,OAAO,CAAC;CACpB;AAoCD;;;;GAIG;AACH,wBAAgB,SAAS,CAAC,EACxB,KAAK,EACL,QAAQ,EACR,OAAO,EACP,WAAW,EACX,KAAK,EACL,OAAO,EACP,aAAa,EACb,MAAkB,EAClB,SAAqB,EACrB,MAAc,EACd,SAAS,EACT,cAAc,EACd,QAAe,EACf,GAAG,KAAK,EACT,EAAE,KAAK,GAAG,GAAG,CAAC,OAAO,CAkJrB"}
|
|
@@ -2,6 +2,23 @@ import { jsx as _jsx, jsxs as _jsxs } from "@harborclient/sdk/jsx-runtime";
|
|
|
2
2
|
import { useId } from '@harborclient/sdk/react';
|
|
3
3
|
import { FieldError } from '../FieldError/index.js';
|
|
4
4
|
import { enhanceControl } from '../enhanceControl.js';
|
|
5
|
+
/**
|
|
6
|
+
* Returns Tailwind classes for the label text based on tone and visibility.
|
|
7
|
+
*
|
|
8
|
+
* @returns Class string for the label element.
|
|
9
|
+
*/
|
|
10
|
+
/**
|
|
11
|
+
* Returns wrapper classes for bordered stacked, checkbox, and inline layouts.
|
|
12
|
+
*
|
|
13
|
+
* @param bordered - Whether the default border and padding should be applied.
|
|
14
|
+
* @param layoutClasses - Layout-specific flex and sizing classes.
|
|
15
|
+
* @param extra - Caller-supplied className override.
|
|
16
|
+
*/
|
|
17
|
+
function borderedWrapperClasses(bordered, layoutClasses, extra) {
|
|
18
|
+
const frame = bordered ? 'p-4 border border-separator rounded-md' : '';
|
|
19
|
+
const base = `hc-form-group ${layoutClasses} ${frame}`.trim();
|
|
20
|
+
return extra ? `${base} ${extra}` : base;
|
|
21
|
+
}
|
|
5
22
|
/**
|
|
6
23
|
* Returns Tailwind classes for the label text based on tone and visibility.
|
|
7
24
|
*
|
|
@@ -22,7 +39,7 @@ function labelClasses(tone, srOnly, inline) {
|
|
|
22
39
|
* Supports stacked fields, checkboxes, inline rows, radio options, and
|
|
23
40
|
* adjacent checkbox rows used in list pickers.
|
|
24
41
|
*/
|
|
25
|
-
export function FormGroup({ label, children, htmlFor, description, error, errorId, descriptionId, layout = 'stacked', labelTone = 'default', srOnly = false, className, labelClassName, ...props }) {
|
|
42
|
+
export function FormGroup({ label, children, htmlFor, description, error, errorId, descriptionId, layout = 'stacked', labelTone = 'default', srOnly = false, className, labelClassName, bordered = true, ...props }) {
|
|
26
43
|
const generatedId = useId();
|
|
27
44
|
const controlId = htmlFor ?? generatedId;
|
|
28
45
|
const extra = className ?? '';
|
|
@@ -63,15 +80,11 @@ export function FormGroup({ label, children, htmlFor, description, error, errorI
|
|
|
63
80
|
id: controlId,
|
|
64
81
|
invalid: resolvedErrorId != null
|
|
65
82
|
});
|
|
66
|
-
const wrapperClasses = extra
|
|
67
|
-
? `hc-form-group flex flex-col gap-1 p-4 border border-separator rounded-md ${extra}`
|
|
68
|
-
: 'hc-form-group flex flex-col gap-1 p-4 border border-separator rounded-md';
|
|
83
|
+
const wrapperClasses = borderedWrapperClasses(bordered, 'flex flex-col gap-1', extra);
|
|
69
84
|
return (_jsxs("div", { ...props, className: wrapperClasses, children: [_jsxs("label", { htmlFor: controlId, className: "hc-form-group-label flex flex-col gap-1", children: [_jsxs("span", { className: "hc-form-group-label-row flex items-center gap-2", children: [linkedChildren, _jsx("span", { className: labelClasses(labelTone, srOnly, false), children: label })] }), resolvedDescriptionId ? (_jsx("p", { id: resolvedDescriptionId, className: "hc-form-group-description m-0 pl-[26px] text-[14px] text-muted", children: description })) : null] }), resolvedErrorId ? (_jsx(FieldError, { id: resolvedErrorId, spacing: "field", children: error })) : null] }));
|
|
70
85
|
}
|
|
71
86
|
if (layout === 'inline') {
|
|
72
|
-
const wrapperClasses = extra
|
|
73
|
-
? `hc-form-group flex min-w-0 flex-1 items-center gap-2 p-4 border border-separator rounded-md ${extra}`
|
|
74
|
-
: 'hc-form-group flex min-w-0 flex-1 items-center gap-2 p-4 border border-separator rounded-md';
|
|
87
|
+
const wrapperClasses = borderedWrapperClasses(bordered, 'flex min-w-0 flex-1 items-center gap-2', extra);
|
|
75
88
|
const linkedChildren = enhanceControl(children, { id: controlId });
|
|
76
89
|
return (_jsxs("label", { htmlFor: controlId, className: wrapperClasses, children: [_jsx("span", { className: labelClasses(labelTone, srOnly, true), children: label }), linkedChildren] }));
|
|
77
90
|
}
|
|
@@ -88,8 +101,6 @@ export function FormGroup({ label, children, htmlFor, description, error, errorI
|
|
|
88
101
|
invalid: resolvedErrorId != null,
|
|
89
102
|
id: htmlFor
|
|
90
103
|
});
|
|
91
|
-
const wrapperClasses = extra
|
|
92
|
-
? `hc-form-group flex flex-col gap-1 p-4 border border-separator rounded-md ${extra}`
|
|
93
|
-
: 'hc-form-group flex flex-col gap-1 p-4 border border-separator rounded-md';
|
|
104
|
+
const wrapperClasses = borderedWrapperClasses(bordered, 'flex flex-col gap-1', extra);
|
|
94
105
|
return (_jsxs("div", { ...props, className: wrapperClasses, children: [_jsxs("label", { htmlFor: htmlFor, className: "hc-form-group-label flex flex-col gap-1", children: [_jsx("span", { className: labelClasses(labelTone, srOnly, false), children: label }), resolvedDescriptionId ? (_jsx("p", { id: resolvedDescriptionId, className: "hc-form-group-description m-0 text-[14px] text-muted", children: description })) : null, control] }), resolvedErrorId ? (_jsx(FieldError, { id: resolvedErrorId, spacing: "field", children: error })) : null] }));
|
|
95
106
|
}
|
|
@@ -0,0 +1,37 @@
|
|
|
1
|
+
import type { JSX, ReactNode } from 'react';
|
|
2
|
+
export interface Props {
|
|
3
|
+
/**
|
|
4
|
+
* Section heading text or node.
|
|
5
|
+
*/
|
|
6
|
+
title: ReactNode;
|
|
7
|
+
/**
|
|
8
|
+
* Helper copy shown below the title.
|
|
9
|
+
*/
|
|
10
|
+
description: ReactNode;
|
|
11
|
+
/**
|
|
12
|
+
* Editor and any trailing controls for this section.
|
|
13
|
+
*/
|
|
14
|
+
children: ReactNode;
|
|
15
|
+
/**
|
|
16
|
+
* When true, stretches the section to fill remaining vertical space in script tabs.
|
|
17
|
+
*/
|
|
18
|
+
fill?: boolean;
|
|
19
|
+
/**
|
|
20
|
+
* Extra classes appended to the outer wrapper.
|
|
21
|
+
*/
|
|
22
|
+
className?: string;
|
|
23
|
+
/**
|
|
24
|
+
* Overrides the default title classes (`text-[18px] text-muted`).
|
|
25
|
+
*/
|
|
26
|
+
titleClassName?: string;
|
|
27
|
+
/**
|
|
28
|
+
* Optional id on the title span for label associations.
|
|
29
|
+
*/
|
|
30
|
+
titleId?: string;
|
|
31
|
+
}
|
|
32
|
+
/**
|
|
33
|
+
* Shared settings section shell: title, description, and editor content.
|
|
34
|
+
* Used across collection, folder, environment, and globals settings views.
|
|
35
|
+
*/
|
|
36
|
+
export declare function FormSection({ title, description, children, fill, className, titleClassName, titleId }: Props): JSX.Element;
|
|
37
|
+
//# sourceMappingURL=index.d.ts.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"index.d.ts","sourceRoot":"","sources":["../../../src/components/FormSection/index.tsx"],"names":[],"mappings":"AAAA,OAAO,KAAK,EAAE,GAAG,EAAE,SAAS,EAAE,MAAM,OAAO,CAAC;AAG5C,MAAM,WAAW,KAAK;IACpB;;OAEG;IACH,KAAK,EAAE,SAAS,CAAC;IAEjB;;OAEG;IACH,WAAW,EAAE,SAAS,CAAC;IAEvB;;OAEG;IACH,QAAQ,EAAE,SAAS,CAAC;IAEpB;;OAEG;IACH,IAAI,CAAC,EAAE,OAAO,CAAC;IAEf;;OAEG;IACH,SAAS,CAAC,EAAE,MAAM,CAAC;IAEnB;;OAEG;IACH,cAAc,CAAC,EAAE,MAAM,CAAC;IAExB;;OAEG;IACH,OAAO,CAAC,EAAE,MAAM,CAAC;CAClB;AAED;;;GAGG;AACH,wBAAgB,WAAW,CAAC,EAC1B,KAAK,EACL,WAAW,EACX,QAAQ,EACR,IAAY,EACZ,SAAS,EACT,cAAc,EACd,OAAO,EACR,EAAE,KAAK,GAAG,GAAG,CAAC,OAAO,CAoBrB"}
|
|
@@ -0,0 +1,9 @@
|
|
|
1
|
+
import { jsx as _jsx, jsxs as _jsxs } from "@harborclient/sdk/jsx-runtime";
|
|
2
|
+
import { cn } from '../utils.js';
|
|
3
|
+
/**
|
|
4
|
+
* Shared settings section shell: title, description, and editor content.
|
|
5
|
+
* Used across collection, folder, environment, and globals settings views.
|
|
6
|
+
*/
|
|
7
|
+
export function FormSection({ title, description, children, fill = false, className, titleClassName, titleId }) {
|
|
8
|
+
return (_jsxs("div", { className: cn('mb-6 flex flex-col gap-1', fill && 'min-h-0 flex-1', className), children: [_jsx("span", { id: titleId, className: cn(titleClassName ?? 'text-[18px] text-muted', fill && 'shrink-0'), children: title }), _jsx("p", { className: cn('hc-form-group-description m-0 mb-2 text-[14px] text-muted', fill && 'shrink-0'), children: description }), children] }));
|
|
9
|
+
}
|
|
@@ -0,0 +1,20 @@
|
|
|
1
|
+
import type { ComponentPropsWithoutRef, JSX } from 'react';
|
|
2
|
+
export interface Props extends Omit<ComponentPropsWithoutRef<'div'>, 'children'> {
|
|
3
|
+
/**
|
|
4
|
+
* Current progress count (for example completed items).
|
|
5
|
+
*/
|
|
6
|
+
value: number;
|
|
7
|
+
/**
|
|
8
|
+
* Maximum progress count (for example total items).
|
|
9
|
+
*/
|
|
10
|
+
max: number;
|
|
11
|
+
/**
|
|
12
|
+
* Accessible name announced for the progress bar.
|
|
13
|
+
*/
|
|
14
|
+
label: string;
|
|
15
|
+
}
|
|
16
|
+
/**
|
|
17
|
+
* Determinate horizontal progress bar with accent fill and width transition.
|
|
18
|
+
*/
|
|
19
|
+
export declare function ProgressBar({ value, max, label, className, ...props }: Props): JSX.Element;
|
|
20
|
+
//# sourceMappingURL=index.d.ts.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"index.d.ts","sourceRoot":"","sources":["../../../src/components/ProgressBar/index.tsx"],"names":[],"mappings":"AAAA,OAAO,KAAK,EAAE,wBAAwB,EAAE,GAAG,EAAE,MAAM,OAAO,CAAC;AAI3D,MAAM,WAAW,KAAM,SAAQ,IAAI,CAAC,wBAAwB,CAAC,KAAK,CAAC,EAAE,UAAU,CAAC;IAC9E;;OAEG;IACH,KAAK,EAAE,MAAM,CAAC;IAEd;;OAEG;IACH,GAAG,EAAE,MAAM,CAAC;IAEZ;;OAEG;IACH,KAAK,EAAE,MAAM,CAAC;CACf;AAED;;GAEG;AACH,wBAAgB,WAAW,CAAC,EAAE,KAAK,EAAE,GAAG,EAAE,KAAK,EAAE,SAAS,EAAE,GAAG,KAAK,EAAE,EAAE,KAAK,GAAG,GAAG,CAAC,OAAO,CAmB1F"}
|
|
@@ -0,0 +1,10 @@
|
|
|
1
|
+
import { jsx as _jsx } from "@harborclient/sdk/jsx-runtime";
|
|
2
|
+
import { cn } from '../utils.js';
|
|
3
|
+
import { progressFillPercent } from './progressBar.logic.js';
|
|
4
|
+
/**
|
|
5
|
+
* Determinate horizontal progress bar with accent fill and width transition.
|
|
6
|
+
*/
|
|
7
|
+
export function ProgressBar({ value, max, label, className, ...props }) {
|
|
8
|
+
const fillPercent = progressFillPercent(value, max);
|
|
9
|
+
return (_jsx("div", { ...props, role: "progressbar", "aria-valuemin": 0, "aria-valuemax": max, "aria-valuenow": value, "aria-label": label, className: cn('hc-progress-bar h-2 overflow-hidden rounded-full bg-separator', className), children: _jsx("div", { className: "hc-progress-bar-fill h-full rounded-full bg-accent transition-[width] duration-200 motion-reduce:transition-none", style: { width: `${fillPercent}%` } }) }));
|
|
10
|
+
}
|
|
@@ -0,0 +1,9 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* Computes the fill width percentage for a determinate progress bar.
|
|
3
|
+
*
|
|
4
|
+
* @param value - Current progress count.
|
|
5
|
+
* @param max - Total count; zero yields 0% to avoid division by zero.
|
|
6
|
+
* @returns Rounded percentage between 0 and 100.
|
|
7
|
+
*/
|
|
8
|
+
export declare function progressFillPercent(value: number, max: number): number;
|
|
9
|
+
//# sourceMappingURL=progressBar.logic.d.ts.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"progressBar.logic.d.ts","sourceRoot":"","sources":["../../../src/components/ProgressBar/progressBar.logic.ts"],"names":[],"mappings":"AAAA;;;;;;GAMG;AACH,wBAAgB,mBAAmB,CAAC,KAAK,EAAE,MAAM,EAAE,GAAG,EAAE,MAAM,GAAG,MAAM,CAKtE"}
|
|
@@ -0,0 +1,13 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* Computes the fill width percentage for a determinate progress bar.
|
|
3
|
+
*
|
|
4
|
+
* @param value - Current progress count.
|
|
5
|
+
* @param max - Total count; zero yields 0% to avoid division by zero.
|
|
6
|
+
* @returns Rounded percentage between 0 and 100.
|
|
7
|
+
*/
|
|
8
|
+
export function progressFillPercent(value, max) {
|
|
9
|
+
if (max === 0) {
|
|
10
|
+
return 0;
|
|
11
|
+
}
|
|
12
|
+
return Math.round((value / max) * 100);
|
|
13
|
+
}
|
|
@@ -0,0 +1,82 @@
|
|
|
1
|
+
import type { JSX, ReactNode } from 'react';
|
|
2
|
+
import type { FormGroupLabelTone } from '../FormGroup/index.js';
|
|
3
|
+
export interface Props {
|
|
4
|
+
/**
|
|
5
|
+
* Dialog heading rendered in the modal header row.
|
|
6
|
+
*/
|
|
7
|
+
title: ReactNode;
|
|
8
|
+
/**
|
|
9
|
+
* Id of the element that labels the dialog (typically the heading).
|
|
10
|
+
*/
|
|
11
|
+
labelledBy: string;
|
|
12
|
+
/**
|
|
13
|
+
* Visible field label, or screen-reader-only text when `srOnlyLabel` is set.
|
|
14
|
+
*/
|
|
15
|
+
label: ReactNode;
|
|
16
|
+
/**
|
|
17
|
+
* Hides the field label visually while keeping it available to screen readers.
|
|
18
|
+
*/
|
|
19
|
+
srOnlyLabel?: boolean;
|
|
20
|
+
/**
|
|
21
|
+
* Label color style for the field. Defaults to muted helper tone.
|
|
22
|
+
*/
|
|
23
|
+
labelTone?: FormGroupLabelTone;
|
|
24
|
+
/**
|
|
25
|
+
* Current input value controlled by the parent.
|
|
26
|
+
*/
|
|
27
|
+
value: string;
|
|
28
|
+
/**
|
|
29
|
+
* Called when the user edits the input value.
|
|
30
|
+
*/
|
|
31
|
+
onChange: (value: string) => void;
|
|
32
|
+
/**
|
|
33
|
+
* Called when the user submits via Enter or the primary button.
|
|
34
|
+
*/
|
|
35
|
+
onSubmit: () => void;
|
|
36
|
+
/**
|
|
37
|
+
* Called when the modal should close.
|
|
38
|
+
*/
|
|
39
|
+
onClose: () => void;
|
|
40
|
+
/**
|
|
41
|
+
* Primary action button label. Defaults to "Save".
|
|
42
|
+
*/
|
|
43
|
+
submitLabel?: string;
|
|
44
|
+
/**
|
|
45
|
+
* Optional placeholder shown when the input is empty.
|
|
46
|
+
*/
|
|
47
|
+
placeholder?: string;
|
|
48
|
+
/**
|
|
49
|
+
* Optional muted helper text rendered below the field label.
|
|
50
|
+
*/
|
|
51
|
+
description?: ReactNode;
|
|
52
|
+
/**
|
|
53
|
+
* Inline validation or submit error rendered below the input.
|
|
54
|
+
*/
|
|
55
|
+
error?: ReactNode;
|
|
56
|
+
/**
|
|
57
|
+
* When true, disables the input and primary button while work is in flight.
|
|
58
|
+
*/
|
|
59
|
+
busy?: boolean;
|
|
60
|
+
/**
|
|
61
|
+
* Custom gate for enabling submit and Enter-to-submit. Defaults to non-empty trimmed value.
|
|
62
|
+
*/
|
|
63
|
+
canSubmit?: (value: string) => boolean;
|
|
64
|
+
/**
|
|
65
|
+
* Optional width class for the dialog panel (passed to {@link Modal}).
|
|
66
|
+
*/
|
|
67
|
+
className?: string;
|
|
68
|
+
/**
|
|
69
|
+
* Explicit id for the text input; used to associate the label via `htmlFor`.
|
|
70
|
+
*/
|
|
71
|
+
inputId?: string;
|
|
72
|
+
/**
|
|
73
|
+
* When true, focuses the input when the modal opens. Defaults to true.
|
|
74
|
+
*/
|
|
75
|
+
autoFocus?: boolean;
|
|
76
|
+
}
|
|
77
|
+
/**
|
|
78
|
+
* Single-field prompt modal with autofocus input, Enter-to-submit, inline error,
|
|
79
|
+
* and a primary action gated on a trimmed non-empty value (or custom `canSubmit`).
|
|
80
|
+
*/
|
|
81
|
+
export declare function PromptModal({ title, labelledBy, label, srOnlyLabel, labelTone, value, onChange, onSubmit, onClose, submitLabel, placeholder, description, error, busy, canSubmit, className, inputId, autoFocus }: Props): JSX.Element;
|
|
82
|
+
//# sourceMappingURL=index.d.ts.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"index.d.ts","sourceRoot":"","sources":["../../../src/components/PromptModal/index.tsx"],"names":[],"mappings":"AAAA,OAAO,KAAK,EAAE,GAAG,EAAiB,SAAS,EAAE,MAAM,OAAO,CAAC;AAE3D,OAAO,KAAK,EAAE,kBAAkB,EAAE,MAAM,uBAAuB,CAAC;AAMhE,MAAM,WAAW,KAAK;IACpB;;OAEG;IACH,KAAK,EAAE,SAAS,CAAC;IAEjB;;OAEG;IACH,UAAU,EAAE,MAAM,CAAC;IAEnB;;OAEG;IACH,KAAK,EAAE,SAAS,CAAC;IAEjB;;OAEG;IACH,WAAW,CAAC,EAAE,OAAO,CAAC;IAEtB;;OAEG;IACH,SAAS,CAAC,EAAE,kBAAkB,CAAC;IAE/B;;OAEG;IACH,KAAK,EAAE,MAAM,CAAC;IAEd;;OAEG;IACH,QAAQ,EAAE,CAAC,KAAK,EAAE,MAAM,KAAK,IAAI,CAAC;IAElC;;OAEG;IACH,QAAQ,EAAE,MAAM,IAAI,CAAC;IAErB;;OAEG;IACH,OAAO,EAAE,MAAM,IAAI,CAAC;IAEpB;;OAEG;IACH,WAAW,CAAC,EAAE,MAAM,CAAC;IAErB;;OAEG;IACH,WAAW,CAAC,EAAE,MAAM,CAAC;IAErB;;OAEG;IACH,WAAW,CAAC,EAAE,SAAS,CAAC;IAExB;;OAEG;IACH,KAAK,CAAC,EAAE,SAAS,CAAC;IAElB;;OAEG;IACH,IAAI,CAAC,EAAE,OAAO,CAAC;IAEf;;OAEG;IACH,SAAS,CAAC,EAAE,CAAC,KAAK,EAAE,MAAM,KAAK,OAAO,CAAC;IAEvC;;OAEG;IACH,SAAS,CAAC,EAAE,MAAM,CAAC;IAEnB;;OAEG;IACH,OAAO,CAAC,EAAE,MAAM,CAAC;IAEjB;;OAEG;IACH,SAAS,CAAC,EAAE,OAAO,CAAC;CACrB;AAED;;;GAGG;AACH,wBAAgB,WAAW,CAAC,EAC1B,KAAK,EACL,UAAU,EACV,KAAK,EACL,WAAmB,EACnB,SAAmB,EACnB,KAAK,EACL,QAAQ,EACR,QAAQ,EACR,OAAO,EACP,WAAoB,EACpB,WAAW,EACX,WAAW,EACX,KAAK,EACL,IAAY,EACZ,SAAuC,EACvC,SAAS,EACT,OAAO,EACP,SAAgB,EACjB,EAAE,KAAK,GAAG,GAAG,CAAC,OAAO,CAyCrB"}
|
|
@@ -0,0 +1,22 @@
|
|
|
1
|
+
import { jsx as _jsx, jsxs as _jsxs } from "@harborclient/sdk/jsx-runtime";
|
|
2
|
+
import { Button } from '../Button/index.js';
|
|
3
|
+
import { FormGroup } from '../FormGroup/index.js';
|
|
4
|
+
import { Modal, ModalFooter } from '../Modal/index.js';
|
|
5
|
+
import { Input } from '../forms/index.js';
|
|
6
|
+
import { defaultCanSubmitPromptValue } from './promptModal.logic.js';
|
|
7
|
+
/**
|
|
8
|
+
* Single-field prompt modal with autofocus input, Enter-to-submit, inline error,
|
|
9
|
+
* and a primary action gated on a trimmed non-empty value (or custom `canSubmit`).
|
|
10
|
+
*/
|
|
11
|
+
export function PromptModal({ title, labelledBy, label, srOnlyLabel = false, labelTone = 'muted', value, onChange, onSubmit, onClose, submitLabel = 'Save', placeholder, description, error, busy = false, canSubmit = defaultCanSubmitPromptValue, className, inputId, autoFocus = true }) {
|
|
12
|
+
const submitEnabled = !busy && canSubmit(value);
|
|
13
|
+
/**
|
|
14
|
+
* Submits the prompt when Enter is pressed and submission is allowed.
|
|
15
|
+
*/
|
|
16
|
+
const handleKeyDown = (event) => {
|
|
17
|
+
if (event.key === 'Enter' && submitEnabled) {
|
|
18
|
+
onSubmit();
|
|
19
|
+
}
|
|
20
|
+
};
|
|
21
|
+
return (_jsxs(Modal, { onClose: onClose, className: className, labelledBy: labelledBy, title: title, children: [_jsx(FormGroup, { label: label, labelTone: labelTone, srOnly: srOnlyLabel, htmlFor: inputId, description: description, error: error, className: "border-none! p-0!", children: _jsx(Input, { className: "w-full", type: "text", autoFocus: autoFocus, placeholder: placeholder, value: value, disabled: busy, onChange: (event) => onChange(event.target.value), onKeyDown: handleKeyDown }) }), _jsx(ModalFooter, { spaced: true, children: _jsx(Button, { disabled: !submitEnabled, onClick: onSubmit, children: submitLabel }) })] }));
|
|
22
|
+
}
|
|
@@ -0,0 +1,8 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* Returns whether a prompt modal value is non-empty after trimming whitespace.
|
|
3
|
+
*
|
|
4
|
+
* @param value - Draft text from the single-field input.
|
|
5
|
+
* @returns True when the trimmed value has at least one character.
|
|
6
|
+
*/
|
|
7
|
+
export declare function defaultCanSubmitPromptValue(value: string): boolean;
|
|
8
|
+
//# sourceMappingURL=promptModal.logic.d.ts.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"promptModal.logic.d.ts","sourceRoot":"","sources":["../../../src/components/PromptModal/promptModal.logic.ts"],"names":[],"mappings":"AAAA;;;;;GAKG;AACH,wBAAgB,2BAA2B,CAAC,KAAK,EAAE,MAAM,GAAG,OAAO,CAElE"}
|
|
@@ -0,0 +1,9 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* Returns whether a prompt modal value is non-empty after trimming whitespace.
|
|
3
|
+
*
|
|
4
|
+
* @param value - Draft text from the single-field input.
|
|
5
|
+
* @returns True when the trimmed value has at least one character.
|
|
6
|
+
*/
|
|
7
|
+
export function defaultCanSubmitPromptValue(value) {
|
|
8
|
+
return value.trim().length > 0;
|
|
9
|
+
}
|
|
@@ -0,0 +1,29 @@
|
|
|
1
|
+
import type { JSX } from 'react';
|
|
2
|
+
interface Props {
|
|
3
|
+
/**
|
|
4
|
+
* Resolved screenshot URLs or data URLs shown in the lightbox.
|
|
5
|
+
*/
|
|
6
|
+
images: string[];
|
|
7
|
+
/**
|
|
8
|
+
* Active slide index shared with the carousel preview.
|
|
9
|
+
*/
|
|
10
|
+
index: number;
|
|
11
|
+
/**
|
|
12
|
+
* Updates the active slide when the user navigates inside the lightbox.
|
|
13
|
+
*/
|
|
14
|
+
onIndexChange: (index: number) => void;
|
|
15
|
+
/**
|
|
16
|
+
* Closes the lightbox overlay.
|
|
17
|
+
*/
|
|
18
|
+
onClose: () => void;
|
|
19
|
+
/**
|
|
20
|
+
* Accessible name for the lightbox dialog.
|
|
21
|
+
*/
|
|
22
|
+
label?: string;
|
|
23
|
+
}
|
|
24
|
+
/**
|
|
25
|
+
* Full-size screenshot preview dialog opened from a screenshot carousel.
|
|
26
|
+
*/
|
|
27
|
+
export declare function ScreenshotLightbox({ images, index, onIndexChange, onClose, label }: Props): JSX.Element;
|
|
28
|
+
export {};
|
|
29
|
+
//# sourceMappingURL=ScreenshotLightbox.d.ts.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"ScreenshotLightbox.d.ts","sourceRoot":"","sources":["../../../src/components/ScreenshotCarousel/ScreenshotLightbox.tsx"],"names":[],"mappings":"AACA,OAAO,KAAK,EAAE,GAAG,EAAiB,MAAM,OAAO,CAAC;AAKhD,UAAU,KAAK;IACb;;OAEG;IACH,MAAM,EAAE,MAAM,EAAE,CAAC;IAEjB;;OAEG;IACH,KAAK,EAAE,MAAM,CAAC;IAEd;;OAEG;IACH,aAAa,EAAE,CAAC,KAAK,EAAE,MAAM,KAAK,IAAI,CAAC;IAEvC;;OAEG;IACH,OAAO,EAAE,MAAM,IAAI,CAAC;IAEpB;;OAEG;IACH,KAAK,CAAC,EAAE,MAAM,CAAC;CAChB;AAMD;;GAEG;AACH,wBAAgB,kBAAkB,CAAC,EACjC,MAAM,EACN,KAAK,EACL,aAAa,EACb,OAAO,EACP,KAA4B,EAC7B,EAAE,KAAK,GAAG,GAAG,CAAC,OAAO,CAqGrB"}
|
|
@@ -0,0 +1,66 @@
|
|
|
1
|
+
import { jsx as _jsx, Fragment as _Fragment, jsxs as _jsxs } from "@harborclient/sdk/jsx-runtime";
|
|
2
|
+
import { faAngleLeft, faAngleRight } from '@fortawesome/free-solid-svg-icons';
|
|
3
|
+
import { useEffect } from 'react';
|
|
4
|
+
import { FaIcon } from '../FaIcon/index.js';
|
|
5
|
+
import { Modal } from '../Modal/index.js';
|
|
6
|
+
/** Shared prev/next control styling for carousel and lightbox navigation. */
|
|
7
|
+
const NAV_BUTTON_CLASS = 'flex h-8 w-8 items-center justify-center rounded-md border border-separator bg-panel/90 text-text shadow-sm hover:bg-selection focus-visible:outline focus-visible:outline-2 focus-visible:outline-offset-2 focus-visible:outline-accent motion-reduce:transition-none';
|
|
8
|
+
/**
|
|
9
|
+
* Full-size screenshot preview dialog opened from a screenshot carousel.
|
|
10
|
+
*/
|
|
11
|
+
export function ScreenshotLightbox({ images, index, onIndexChange, onClose, label = 'Screenshot preview' }) {
|
|
12
|
+
const imageCount = images.length;
|
|
13
|
+
const currentIndex = Math.min(index, imageCount - 1);
|
|
14
|
+
const hasMultiple = imageCount > 1;
|
|
15
|
+
const currentImage = images[currentIndex];
|
|
16
|
+
/**
|
|
17
|
+
* Closes the lightbox on Escape without dismissing a parent dialog beneath it.
|
|
18
|
+
*/
|
|
19
|
+
useEffect(() => {
|
|
20
|
+
/**
|
|
21
|
+
* Handles Escape in the capture phase so nested modals stay open.
|
|
22
|
+
*
|
|
23
|
+
* @param event - Document keydown event.
|
|
24
|
+
*/
|
|
25
|
+
const handleKeyDown = (event) => {
|
|
26
|
+
if (event.key === 'Escape') {
|
|
27
|
+
event.stopImmediatePropagation();
|
|
28
|
+
onClose();
|
|
29
|
+
}
|
|
30
|
+
};
|
|
31
|
+
document.addEventListener('keydown', handleKeyDown, true);
|
|
32
|
+
return () => document.removeEventListener('keydown', handleKeyDown, true);
|
|
33
|
+
}, [onClose]);
|
|
34
|
+
/**
|
|
35
|
+
* Moves to the previous screenshot, wrapping to the last slide.
|
|
36
|
+
*/
|
|
37
|
+
const showPrevious = () => {
|
|
38
|
+
onIndexChange(currentIndex === 0 ? imageCount - 1 : currentIndex - 1);
|
|
39
|
+
};
|
|
40
|
+
/**
|
|
41
|
+
* Moves to the next screenshot, wrapping to the first slide.
|
|
42
|
+
*/
|
|
43
|
+
const showNext = () => {
|
|
44
|
+
onIndexChange(currentIndex === imageCount - 1 ? 0 : currentIndex + 1);
|
|
45
|
+
};
|
|
46
|
+
/**
|
|
47
|
+
* Handles keyboard navigation within the lightbox dialog.
|
|
48
|
+
*
|
|
49
|
+
* @param event - Keyboard event on the lightbox container.
|
|
50
|
+
*/
|
|
51
|
+
const handleKeyDown = (event) => {
|
|
52
|
+
if (!hasMultiple) {
|
|
53
|
+
return;
|
|
54
|
+
}
|
|
55
|
+
if (event.key === 'ArrowLeft') {
|
|
56
|
+
event.preventDefault();
|
|
57
|
+
showPrevious();
|
|
58
|
+
return;
|
|
59
|
+
}
|
|
60
|
+
if (event.key === 'ArrowRight') {
|
|
61
|
+
event.preventDefault();
|
|
62
|
+
showNext();
|
|
63
|
+
}
|
|
64
|
+
};
|
|
65
|
+
return (_jsx(Modal, { label: label, onClose: onClose, disableEscape: true, overlayClassName: "z-[60]", className: "relative flex max-h-[90vh] w-[min(92vw,72rem)] items-center justify-center p-2", children: _jsxs("div", { className: "relative flex w-full items-center justify-center", onKeyDown: handleKeyDown, children: [_jsx("img", { src: currentImage, alt: "", className: "max-h-[85vh] max-w-full object-contain" }), hasMultiple ? (_jsxs(_Fragment, { children: [_jsx("button", { type: "button", className: `absolute top-1/2 left-2 -translate-y-1/2 ${NAV_BUTTON_CLASS}`, "aria-label": "Previous screenshot", onClick: showPrevious, children: _jsx(FaIcon, { icon: faAngleLeft, className: "h-3.5 w-3.5" }) }), _jsx("button", { type: "button", className: `absolute top-1/2 right-2 -translate-y-1/2 ${NAV_BUTTON_CLASS}`, "aria-label": "Next screenshot", onClick: showNext, children: _jsx(FaIcon, { icon: faAngleRight, className: "h-3.5 w-3.5" }) }), _jsx("p", { className: "sr-only", role: "status", "aria-live": "polite", children: `Screenshot ${currentIndex + 1} of ${imageCount}` })] })) : null] }) }));
|
|
66
|
+
}
|