@harborclient/sdk 1.1.13 → 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.
Files changed (61) hide show
  1. package/dist/components/Badge/index.d.ts +1 -1
  2. package/dist/components/Badge/index.d.ts.map +1 -1
  3. package/dist/components/Badge/index.js +2 -0
  4. package/dist/components/CatalogCard/index.d.ts +51 -0
  5. package/dist/components/CatalogCard/index.d.ts.map +1 -0
  6. package/dist/components/CatalogCard/index.js +23 -0
  7. package/dist/components/CatalogReadmeMarkdown/index.d.ts +13 -0
  8. package/dist/components/CatalogReadmeMarkdown/index.d.ts.map +1 -0
  9. package/dist/components/CatalogReadmeMarkdown/index.js +53 -0
  10. package/dist/components/FormGroup/index.d.ts +6 -1
  11. package/dist/components/FormGroup/index.d.ts.map +1 -1
  12. package/dist/components/FormGroup/index.js +21 -10
  13. package/dist/components/FormSection/index.d.ts +37 -0
  14. package/dist/components/FormSection/index.d.ts.map +1 -0
  15. package/dist/components/FormSection/index.js +9 -0
  16. package/dist/components/ProgressBar/index.d.ts +20 -0
  17. package/dist/components/ProgressBar/index.d.ts.map +1 -0
  18. package/dist/components/ProgressBar/index.js +10 -0
  19. package/dist/components/ProgressBar/progressBar.logic.d.ts +9 -0
  20. package/dist/components/ProgressBar/progressBar.logic.d.ts.map +1 -0
  21. package/dist/components/ProgressBar/progressBar.logic.js +13 -0
  22. package/dist/components/PromptModal/index.d.ts +82 -0
  23. package/dist/components/PromptModal/index.d.ts.map +1 -0
  24. package/dist/components/PromptModal/index.js +22 -0
  25. package/dist/components/PromptModal/promptModal.logic.d.ts +8 -0
  26. package/dist/components/PromptModal/promptModal.logic.d.ts.map +1 -0
  27. package/dist/components/PromptModal/promptModal.logic.js +9 -0
  28. package/dist/components/ScreenshotCarousel/ScreenshotLightbox.d.ts +29 -0
  29. package/dist/components/ScreenshotCarousel/ScreenshotLightbox.d.ts.map +1 -0
  30. package/dist/components/ScreenshotCarousel/ScreenshotLightbox.js +66 -0
  31. package/dist/components/ScreenshotCarousel/index.d.ts +35 -0
  32. package/dist/components/ScreenshotCarousel/index.d.ts.map +1 -0
  33. package/dist/components/ScreenshotCarousel/index.js +89 -0
  34. package/dist/components/ScreenshotCarousel/variants.d.ts +17 -0
  35. package/dist/components/ScreenshotCarousel/variants.d.ts.map +1 -0
  36. package/dist/components/ScreenshotCarousel/variants.js +22 -0
  37. package/dist/components/SelectionActionToolbar/index.d.ts +41 -0
  38. package/dist/components/SelectionActionToolbar/index.d.ts.map +1 -0
  39. package/dist/components/SelectionActionToolbar/index.js +13 -0
  40. package/dist/components/SettingIdLabel/index.d.ts +16 -0
  41. package/dist/components/SettingIdLabel/index.d.ts.map +1 -0
  42. package/dist/components/SettingIdLabel/index.js +7 -0
  43. package/dist/components/SettingSectionHeading/index.d.ts +33 -0
  44. package/dist/components/SettingSectionHeading/index.d.ts.map +1 -0
  45. package/dist/components/SettingSectionHeading/index.js +10 -0
  46. package/dist/components/SidebarItem/index.d.ts +1 -1
  47. package/dist/components/SidebarItem/index.d.ts.map +1 -1
  48. package/dist/components/SidebarItem/index.js +1 -1
  49. package/dist/components/SidebarItem/sidebarItemClasses.d.ts +8 -0
  50. package/dist/components/SidebarItem/sidebarItemClasses.d.ts.map +1 -1
  51. package/dist/components/SidebarItem/sidebarItemClasses.js +18 -8
  52. package/dist/components/StatusDot/index.d.ts +42 -0
  53. package/dist/components/StatusDot/index.d.ts.map +1 -0
  54. package/dist/components/StatusDot/index.js +42 -0
  55. package/dist/components/ThemeVariantPickerModal/index.d.ts +71 -0
  56. package/dist/components/ThemeVariantPickerModal/index.d.ts.map +1 -0
  57. package/dist/components/ThemeVariantPickerModal/index.js +37 -0
  58. package/dist/components/index.d.ts +24 -1
  59. package/dist/components/index.d.ts.map +1 -1
  60. package/dist/components/index.js +15 -1
  61. package/package.json +6 -2
@@ -0,0 +1,35 @@
1
+ import type { JSX } from 'react';
2
+ import { type ScreenshotCarouselVariant } from './variants.js';
3
+ interface Props {
4
+ /**
5
+ * Resolved screenshot URLs or data URLs to display.
6
+ */
7
+ images: string[];
8
+ /**
9
+ * Visual context for card grid, detail modal, or page tab spacing.
10
+ */
11
+ variant: ScreenshotCarouselVariant;
12
+ /**
13
+ * Accessible name for the carousel group.
14
+ */
15
+ ariaLabel?: string;
16
+ /**
17
+ * Accessible name for the full-size lightbox dialog.
18
+ */
19
+ lightboxLabel?: string;
20
+ /**
21
+ * Optional wrapper class names.
22
+ */
23
+ className?: string;
24
+ /**
25
+ * Stops pointer and keyboard events from bubbling to a parent activator.
26
+ * Used by marketplace cards that open a modal on click.
27
+ */
28
+ stopPropagation?: boolean;
29
+ }
30
+ /**
31
+ * Accessible left/right screenshot carousel for marketplace previews.
32
+ */
33
+ export declare function ScreenshotCarousel({ images, variant, ariaLabel, lightboxLabel, className, stopPropagation }: Props): JSX.Element | null;
34
+ export {};
35
+ //# sourceMappingURL=index.d.ts.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"index.d.ts","sourceRoot":"","sources":["../../../src/components/ScreenshotCarousel/index.tsx"],"names":[],"mappings":"AACA,OAAO,KAAK,EAAE,GAAG,EAA6B,MAAM,OAAO,CAAC;AAI5D,OAAO,EACL,KAAK,yBAAyB,EAG/B,MAAM,eAAe,CAAC;AAEvB,UAAU,KAAK;IACb;;OAEG;IACH,MAAM,EAAE,MAAM,EAAE,CAAC;IAEjB;;OAEG;IACH,OAAO,EAAE,yBAAyB,CAAC;IAEnC;;OAEG;IACH,SAAS,CAAC,EAAE,MAAM,CAAC;IAEnB;;OAEG;IACH,aAAa,CAAC,EAAE,MAAM,CAAC;IAEvB;;OAEG;IACH,SAAS,CAAC,EAAE,MAAM,CAAC;IAEnB;;;OAGG;IACH,eAAe,CAAC,EAAE,OAAO,CAAC;CAC3B;AAED;;GAEG;AACH,wBAAgB,kBAAkB,CAAC,EACjC,MAAM,EACN,OAAO,EACP,SAAyB,EACzB,aAAoC,EACpC,SAAS,EACT,eAAuB,EACxB,EAAE,KAAK,GAAG,GAAG,CAAC,OAAO,GAAG,IAAI,CAmK5B"}
@@ -0,0 +1,89 @@
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 { useState } from 'react';
4
+ import { FaIcon } from '../FaIcon/index.js';
5
+ import { ScreenshotLightbox } from './ScreenshotLightbox.js';
6
+ import { screenshotCarouselImageFrameClassName, screenshotCarouselLightboxEnabled } from './variants.js';
7
+ /**
8
+ * Accessible left/right screenshot carousel for marketplace previews.
9
+ */
10
+ export function ScreenshotCarousel({ images, variant, ariaLabel = 'Screenshots', lightboxLabel = 'Screenshot preview', className, stopPropagation = false }) {
11
+ const [index, setIndex] = useState(0);
12
+ const [lightboxOpen, setLightboxOpen] = useState(false);
13
+ const imageCount = images.length;
14
+ const currentIndex = imageCount === 0 ? 0 : Math.min(index, imageCount - 1);
15
+ if (imageCount === 0) {
16
+ return null;
17
+ }
18
+ const hasMultiple = imageCount > 1;
19
+ const currentImage = images[currentIndex];
20
+ const lightboxEnabled = screenshotCarouselLightboxEnabled(variant);
21
+ /**
22
+ * Moves to the previous screenshot, wrapping to the last slide.
23
+ */
24
+ const showPrevious = () => {
25
+ setIndex(currentIndex === 0 ? imageCount - 1 : currentIndex - 1);
26
+ };
27
+ /**
28
+ * Moves to the next screenshot, wrapping to the first slide.
29
+ */
30
+ const showNext = () => {
31
+ setIndex(currentIndex === imageCount - 1 ? 0 : currentIndex + 1);
32
+ };
33
+ /**
34
+ * Handles keyboard navigation within the carousel group.
35
+ *
36
+ * @param event - Keyboard event on the carousel container.
37
+ */
38
+ const handleKeyDown = (event) => {
39
+ if (!hasMultiple) {
40
+ return;
41
+ }
42
+ if (event.key === 'ArrowLeft') {
43
+ event.preventDefault();
44
+ showPrevious();
45
+ return;
46
+ }
47
+ if (event.key === 'ArrowRight') {
48
+ event.preventDefault();
49
+ showNext();
50
+ }
51
+ };
52
+ /**
53
+ * Prevents carousel controls from activating a parent card click handler.
54
+ *
55
+ * @param event - Pointer event from a carousel control.
56
+ */
57
+ const handleControlPointerEvent = (event) => {
58
+ if (stopPropagation) {
59
+ event.stopPropagation();
60
+ }
61
+ };
62
+ /**
63
+ * Prevents carousel keyboard activation from opening a parent card.
64
+ *
65
+ * @param event - Keyboard event from a carousel control.
66
+ */
67
+ const handleControlKeyDown = (event) => {
68
+ if (stopPropagation) {
69
+ event.stopPropagation();
70
+ }
71
+ };
72
+ /**
73
+ * Opens the full-size screenshot lightbox for modal and tab detail views.
74
+ */
75
+ const handleOpenLightbox = () => {
76
+ setLightboxOpen(true);
77
+ };
78
+ const frameClassName = screenshotCarouselImageFrameClassName(variant);
79
+ const previewLabel = hasMultiple
80
+ ? `View screenshot ${currentIndex + 1} of ${imageCount} in full size`
81
+ : 'View screenshot in full size';
82
+ return (_jsxs("div", { className: className ?? 'relative', role: "group", "aria-roledescription": "carousel", "aria-label": ariaLabel, tabIndex: hasMultiple ? 0 : undefined, onKeyDown: handleKeyDown, children: [lightboxEnabled ? (_jsx("button", { type: "button", className: "mb-4 block w-full cursor-zoom-in border-none bg-transparent p-0 focus-visible:outline focus-visible:outline-2 focus-visible:outline-offset-2 focus-visible:outline-accent", "aria-label": previewLabel, onClick: handleOpenLightbox, children: _jsx("img", { src: currentImage, alt: "", "aria-hidden": true, className: frameClassName }) })) : (_jsx("img", { src: currentImage, alt: "", "aria-hidden": true, className: frameClassName })), lightboxEnabled && lightboxOpen ? (_jsx(ScreenshotLightbox, { images: images, index: currentIndex, onIndexChange: setIndex, onClose: () => setLightboxOpen(false), label: lightboxLabel })) : null, hasMultiple ? (_jsxs(_Fragment, { children: [_jsx("button", { type: "button", className: "bg-panel/90 absolute top-1/2 left-2 flex h-8 w-8 -translate-y-1/2 items-center justify-center rounded-md border border-separator 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", "aria-label": "Previous screenshot", onClick: (event) => {
83
+ handleControlPointerEvent(event);
84
+ showPrevious();
85
+ }, onKeyDown: handleControlKeyDown, children: _jsx(FaIcon, { icon: faAngleLeft, className: "h-3.5 w-3.5" }) }), _jsx("button", { type: "button", className: "bg-panel/90 absolute top-1/2 right-2 flex h-8 w-8 -translate-y-1/2 items-center justify-center rounded-md border border-separator 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", "aria-label": "Next screenshot", onClick: (event) => {
86
+ handleControlPointerEvent(event);
87
+ showNext();
88
+ }, onKeyDown: handleControlKeyDown, 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}` }), _jsx("div", { className: "pointer-events-none absolute bottom-2 left-1/2 flex -translate-x-1/2 gap-1.5", "aria-hidden": true, children: images.map((image, dotIndex) => (_jsx("span", { className: `h-2 w-2 rounded-full ${dotIndex === currentIndex ? 'bg-text' : 'bg-text/40'}` }, `${image}-${dotIndex}`))) })] })) : null] }));
89
+ }
@@ -0,0 +1,17 @@
1
+ /**
2
+ * Screenshot carousel layout variant.
3
+ */
4
+ export type ScreenshotCarouselVariant = 'card' | 'modal' | 'tab';
5
+ /**
6
+ * Returns the image frame classes for card, modal, and tab variants.
7
+ *
8
+ * @param variant - Card grid, detail modal, or page tab layout.
9
+ */
10
+ export declare function screenshotCarouselImageFrameClassName(variant: ScreenshotCarouselVariant): string;
11
+ /**
12
+ * Returns whether the carousel should open a full-size lightbox on click.
13
+ *
14
+ * @param variant - Card grid, detail modal, or page tab layout.
15
+ */
16
+ export declare function screenshotCarouselLightboxEnabled(variant: ScreenshotCarouselVariant): boolean;
17
+ //# sourceMappingURL=variants.d.ts.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"variants.d.ts","sourceRoot":"","sources":["../../../src/components/ScreenshotCarousel/variants.ts"],"names":[],"mappings":"AAAA;;GAEG;AACH,MAAM,MAAM,yBAAyB,GAAG,MAAM,GAAG,OAAO,GAAG,KAAK,CAAC;AAEjE;;;;GAIG;AACH,wBAAgB,qCAAqC,CAAC,OAAO,EAAE,yBAAyB,GAAG,MAAM,CAQhG;AAED;;;;GAIG;AACH,wBAAgB,iCAAiC,CAAC,OAAO,EAAE,yBAAyB,GAAG,OAAO,CAE7F"}
@@ -0,0 +1,22 @@
1
+ /**
2
+ * Returns the image frame classes for card, modal, and tab variants.
3
+ *
4
+ * @param variant - Card grid, detail modal, or page tab layout.
5
+ */
6
+ export function screenshotCarouselImageFrameClassName(variant) {
7
+ if (variant === 'card') {
8
+ return 'aspect-video w-full object-cover object-top border-b border-separator';
9
+ }
10
+ if (variant === 'tab') {
11
+ return 'max-h-[min(18rem,35vh)] w-full rounded-md border border-separator object-contain object-top';
12
+ }
13
+ return 'aspect-video w-full object-cover object-top rounded-md border border-separator';
14
+ }
15
+ /**
16
+ * Returns whether the carousel should open a full-size lightbox on click.
17
+ *
18
+ * @param variant - Card grid, detail modal, or page tab layout.
19
+ */
20
+ export function screenshotCarouselLightboxEnabled(variant) {
21
+ return variant === 'modal' || variant === 'tab';
22
+ }
@@ -0,0 +1,41 @@
1
+ import type { IconDefinition } from '@fortawesome/fontawesome-svg-core';
2
+ import type { JSX } from 'react';
3
+ export interface Props {
4
+ /**
5
+ * Fixed viewport coordinates for the floating toolbar button.
6
+ */
7
+ coords: {
8
+ top: number;
9
+ left: number;
10
+ };
11
+ /**
12
+ * Accessible name announced for the action button.
13
+ */
14
+ label: string;
15
+ /**
16
+ * Visible button label, for example "Copy to chat".
17
+ */
18
+ text: string;
19
+ /**
20
+ * Invoked when the user activates the selection action.
21
+ */
22
+ onSelect: () => void;
23
+ /**
24
+ * Optional leading icon rendered before the visible label.
25
+ */
26
+ icon?: IconDefinition;
27
+ /**
28
+ * Optional muted shortcut hint shown after the label.
29
+ */
30
+ shortcutHint?: string;
31
+ /**
32
+ * Additional classes merged onto the toolbar button.
33
+ */
34
+ className?: string;
35
+ }
36
+ /**
37
+ * Floating selection action button portaled to document.body so fixed positioning
38
+ * is not clipped by overflow-hidden editor or terminal containers.
39
+ */
40
+ export declare function SelectionActionToolbar({ coords, label, text, onSelect, icon, shortcutHint, className }: Props): JSX.Element;
41
+ //# sourceMappingURL=index.d.ts.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"index.d.ts","sourceRoot":"","sources":["../../../src/components/SelectionActionToolbar/index.tsx"],"names":[],"mappings":"AAAA,OAAO,KAAK,EAAE,cAAc,EAAE,MAAM,mCAAmC,CAAC;AACxE,OAAO,KAAK,EAAE,GAAG,EAAE,MAAM,OAAO,CAAC;AAKjC,MAAM,WAAW,KAAK;IACpB;;OAEG;IACH,MAAM,EAAE;QAAE,GAAG,EAAE,MAAM,CAAC;QAAC,IAAI,EAAE,MAAM,CAAA;KAAE,CAAC;IAEtC;;OAEG;IACH,KAAK,EAAE,MAAM,CAAC;IAEd;;OAEG;IACH,IAAI,EAAE,MAAM,CAAC;IAEb;;OAEG;IACH,QAAQ,EAAE,MAAM,IAAI,CAAC;IAErB;;OAEG;IACH,IAAI,CAAC,EAAE,cAAc,CAAC;IAEtB;;OAEG;IACH,YAAY,CAAC,EAAE,MAAM,CAAC;IAEtB;;OAEG;IACH,SAAS,CAAC,EAAE,MAAM,CAAC;CACpB;AAED;;;GAGG;AACH,wBAAgB,sBAAsB,CAAC,EACrC,MAAM,EACN,KAAK,EACL,IAAI,EACJ,QAAQ,EACR,IAAI,EACJ,YAAY,EACZ,SAAS,EACV,EAAE,KAAK,GAAG,GAAG,CAAC,OAAO,CAoBrB"}
@@ -0,0 +1,13 @@
1
+ import { jsx as _jsx, jsxs as _jsxs } from "@harborclient/sdk/jsx-runtime";
2
+ import { FaIcon } from '../FaIcon/index.js';
3
+ import { portalToBody } from '../portalToBody.js';
4
+ import { cn } from '../utils.js';
5
+ /**
6
+ * Floating selection action button portaled to document.body so fixed positioning
7
+ * is not clipped by overflow-hidden editor or terminal containers.
8
+ */
9
+ export function SelectionActionToolbar({ coords, label, text, onSelect, icon, shortcutHint, className }) {
10
+ return portalToBody(_jsxs("button", { type: "button", className: cn('hc-code-editor-selection-action app-no-drag pointer-events-auto fixed z-[70] inline-flex cursor-pointer items-center gap-1.5 rounded-md border border-separator bg-control px-2 py-1 text-[14px] text-text shadow-sm hover:bg-surface focus-visible:outline focus-visible:outline-2 focus-visible:outline-offset-1 focus-visible:outline-accent', className), style: { top: coords.top, left: coords.left }, "aria-label": label, onMouseDown: (event) => {
11
+ event.preventDefault();
12
+ }, onClick: onSelect, children: [icon ? _jsx(FaIcon, { icon: icon, className: "h-3.5 w-3.5" }) : null, _jsx("span", { children: text }), shortcutHint ? _jsx("span", { className: "text-[14px] text-muted", children: shortcutHint }) : null] }));
13
+ }
@@ -0,0 +1,16 @@
1
+ import type { JSX, ReactNode } from 'react';
2
+ export interface Props {
3
+ /**
4
+ * Visible setting label text.
5
+ */
6
+ children: ReactNode;
7
+ /**
8
+ * Stable setting id shown on hover and keyboard focus.
9
+ */
10
+ settingId: string;
11
+ }
12
+ /**
13
+ * Setting label with a VS Code-style id affordance revealed on hover and focus.
14
+ */
15
+ export declare function SettingIdLabel({ children, settingId }: Props): JSX.Element;
16
+ //# sourceMappingURL=index.d.ts.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"index.d.ts","sourceRoot":"","sources":["../../../src/components/SettingIdLabel/index.tsx"],"names":[],"mappings":"AAAA,OAAO,KAAK,EAAE,GAAG,EAAE,SAAS,EAAE,MAAM,OAAO,CAAC;AAE5C,MAAM,WAAW,KAAK;IACpB;;OAEG;IACH,QAAQ,EAAE,SAAS,CAAC;IAEpB;;OAEG;IACH,SAAS,EAAE,MAAM,CAAC;CACnB;AAED;;GAEG;AACH,wBAAgB,cAAc,CAAC,EAAE,QAAQ,EAAE,SAAS,EAAE,EAAE,KAAK,GAAG,GAAG,CAAC,OAAO,CAa1E"}
@@ -0,0 +1,7 @@
1
+ import { jsx as _jsx, jsxs as _jsxs } from "@harborclient/sdk/jsx-runtime";
2
+ /**
3
+ * Setting label with a VS Code-style id affordance revealed on hover and focus.
4
+ */
5
+ export function SettingIdLabel({ children, settingId }) {
6
+ return (_jsxs("span", { className: "group/setting-label inline-flex items-baseline gap-2", children: [_jsx("span", { children: children }), _jsx("span", { className: "pointer-events-none font-mono text-[14px] text-muted opacity-0 transition-opacity select-none group-focus-within/setting-label:opacity-100 group-hover/setting-label:opacity-100", title: settingId, "aria-label": `Setting id: ${settingId}`, children: settingId })] }));
7
+ }
@@ -0,0 +1,33 @@
1
+ import type { JSX, ReactNode } from 'react';
2
+ export interface Props {
3
+ /**
4
+ * Stable setting id shown on hover and keyboard focus beside the title.
5
+ */
6
+ settingId: string;
7
+ /**
8
+ * Visible section title text.
9
+ */
10
+ title: ReactNode;
11
+ /**
12
+ * Optional muted helper copy rendered below the title.
13
+ */
14
+ description?: ReactNode;
15
+ /**
16
+ * Extra classes on the outer wrapper.
17
+ */
18
+ className?: string;
19
+ /**
20
+ * Overrides the default title span classes.
21
+ */
22
+ titleClassName?: string;
23
+ /**
24
+ * Overrides the default description paragraph classes.
25
+ */
26
+ descriptionClassName?: string;
27
+ }
28
+ /**
29
+ * Settings section heading that pairs a titled label with an optional description
30
+ * and a hover-revealed setting id badge.
31
+ */
32
+ export declare function SettingSectionHeading({ settingId, title, description, className, titleClassName, descriptionClassName }: Props): JSX.Element;
33
+ //# sourceMappingURL=index.d.ts.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"index.d.ts","sourceRoot":"","sources":["../../../src/components/SettingSectionHeading/index.tsx"],"names":[],"mappings":"AAAA,OAAO,KAAK,EAAE,GAAG,EAAE,SAAS,EAAE,MAAM,OAAO,CAAC;AAI5C,MAAM,WAAW,KAAK;IACpB;;OAEG;IACH,SAAS,EAAE,MAAM,CAAC;IAElB;;OAEG;IACH,KAAK,EAAE,SAAS,CAAC;IAEjB;;OAEG;IACH,WAAW,CAAC,EAAE,SAAS,CAAC;IAExB;;OAEG;IACH,SAAS,CAAC,EAAE,MAAM,CAAC;IAEnB;;OAEG;IACH,cAAc,CAAC,EAAE,MAAM,CAAC;IAExB;;OAEG;IACH,oBAAoB,CAAC,EAAE,MAAM,CAAC;CAC/B;AAED;;;GAGG;AACH,wBAAgB,qBAAqB,CAAC,EACpC,SAAS,EACT,KAAK,EACL,WAAW,EACX,SAAS,EACT,cAAc,EACd,oBAAoB,EACrB,EAAE,KAAK,GAAG,GAAG,CAAC,OAAO,CAWrB"}
@@ -0,0 +1,10 @@
1
+ import { jsx as _jsx, jsxs as _jsxs } from "@harborclient/sdk/jsx-runtime";
2
+ import { SettingIdLabel } from '../SettingIdLabel/index.js';
3
+ import { cn } from '../utils.js';
4
+ /**
5
+ * Settings section heading that pairs a titled label with an optional description
6
+ * and a hover-revealed setting id badge.
7
+ */
8
+ export function SettingSectionHeading({ settingId, title, description, className, titleClassName, descriptionClassName }) {
9
+ return (_jsxs("div", { className: className, children: [_jsx("span", { className: cn('text-[18px] font-medium text-text', titleClassName), children: _jsx(SettingIdLabel, { settingId: settingId, children: title }) }), description != null && description !== '' ? (_jsx("p", { className: cn('m-0 mb-4 text-muted', descriptionClassName), children: description })) : null] }));
10
+ }
@@ -7,7 +7,7 @@ export { SortableSidebarItem } from './SortableSidebarItem.js';
7
7
  export { stopSortableDragPointerDown } from './stopSortableDragPointerDown.js';
8
8
  export { SidebarColorDot } from './SidebarColorDot.js';
9
9
  export { SidebarBadge, type SidebarBadgeVariant } from './SidebarBadge.js';
10
- export { sourceRow, METHOD_CLASSES, statusDotClass, SIDEBAR_ITEM_BUTTON_CLASS } from './sidebarItemClasses.js';
10
+ export { sourceRow, METHOD_CLASSES, statusDotVariant, statusDotClass, SIDEBAR_ITEM_BUTTON_CLASS } from './sidebarItemClasses.js';
11
11
  export { SidebarMethodBadge } from './SidebarMethodBadge.js';
12
12
  export { SidebarStatusDot } from './SidebarStatusDot.js';
13
13
  export { SidebarStatusMarker } from './SidebarStatusMarker.js';
@@ -1 +1 @@
1
- {"version":3,"file":"index.d.ts","sourceRoot":"","sources":["../../../src/components/SidebarItem/index.tsx"],"names":[],"mappings":"AAAA,OAAO,EACL,WAAW,EACX,KAAK,wBAAwB,EAC7B,KAAK,yBAAyB,EAC9B,KAAK,mBAAmB,EACzB,MAAM,kBAAkB,CAAC;AAC1B,OAAO,EAAE,cAAc,EAAE,MAAM,qBAAqB,CAAC;AACrD,OAAO,EAAE,WAAW,EAAE,MAAM,kBAAkB,CAAC;AAC/C,OAAO,EAAE,WAAW,EAAE,gBAAgB,EAAE,MAAM,kBAAkB,CAAC;AACjE,OAAO,EAAE,0BAA0B,EAAE,MAAM,wBAAwB,CAAC;AACpE,OAAO,EAAE,mBAAmB,EAAE,MAAM,0BAA0B,CAAC;AAC/D,OAAO,EAAE,2BAA2B,EAAE,MAAM,kCAAkC,CAAC;AAC/E,OAAO,EAAE,eAAe,EAAE,MAAM,sBAAsB,CAAC;AACvD,OAAO,EAAE,YAAY,EAAE,KAAK,mBAAmB,EAAE,MAAM,mBAAmB,CAAC;AAC3E,OAAO,EACL,SAAS,EACT,cAAc,EACd,cAAc,EACd,yBAAyB,EAC1B,MAAM,yBAAyB,CAAC;AACjC,OAAO,EAAE,kBAAkB,EAAE,MAAM,yBAAyB,CAAC;AAC7D,OAAO,EAAE,gBAAgB,EAAE,MAAM,uBAAuB,CAAC;AACzD,OAAO,EAAE,mBAAmB,EAAE,MAAM,0BAA0B,CAAC;AAC/D,OAAO,EAAE,kBAAkB,EAAE,mBAAmB,EAAE,MAAM,yBAAyB,CAAC;AAClF,OAAO,EAAE,iBAAiB,EAAE,MAAM,wBAAwB,CAAC;AAC3D,OAAO,EAAE,cAAc,EAAE,MAAM,qBAAqB,CAAC;AACrD,OAAO,EAAE,kBAAkB,EAAE,MAAM,yBAAyB,CAAC;AAC7D,OAAO,EAAE,sBAAsB,EAAE,MAAM,6BAA6B,CAAC;AACrE,OAAO,EAAE,mBAAmB,EAAE,MAAM,0BAA0B,CAAC;AAC/D,OAAO,EAAE,iBAAiB,EAAE,MAAM,wBAAwB,CAAC"}
1
+ {"version":3,"file":"index.d.ts","sourceRoot":"","sources":["../../../src/components/SidebarItem/index.tsx"],"names":[],"mappings":"AAAA,OAAO,EACL,WAAW,EACX,KAAK,wBAAwB,EAC7B,KAAK,yBAAyB,EAC9B,KAAK,mBAAmB,EACzB,MAAM,kBAAkB,CAAC;AAC1B,OAAO,EAAE,cAAc,EAAE,MAAM,qBAAqB,CAAC;AACrD,OAAO,EAAE,WAAW,EAAE,MAAM,kBAAkB,CAAC;AAC/C,OAAO,EAAE,WAAW,EAAE,gBAAgB,EAAE,MAAM,kBAAkB,CAAC;AACjE,OAAO,EAAE,0BAA0B,EAAE,MAAM,wBAAwB,CAAC;AACpE,OAAO,EAAE,mBAAmB,EAAE,MAAM,0BAA0B,CAAC;AAC/D,OAAO,EAAE,2BAA2B,EAAE,MAAM,kCAAkC,CAAC;AAC/E,OAAO,EAAE,eAAe,EAAE,MAAM,sBAAsB,CAAC;AACvD,OAAO,EAAE,YAAY,EAAE,KAAK,mBAAmB,EAAE,MAAM,mBAAmB,CAAC;AAC3E,OAAO,EACL,SAAS,EACT,cAAc,EACd,gBAAgB,EAChB,cAAc,EACd,yBAAyB,EAC1B,MAAM,yBAAyB,CAAC;AACjC,OAAO,EAAE,kBAAkB,EAAE,MAAM,yBAAyB,CAAC;AAC7D,OAAO,EAAE,gBAAgB,EAAE,MAAM,uBAAuB,CAAC;AACzD,OAAO,EAAE,mBAAmB,EAAE,MAAM,0BAA0B,CAAC;AAC/D,OAAO,EAAE,kBAAkB,EAAE,mBAAmB,EAAE,MAAM,yBAAyB,CAAC;AAClF,OAAO,EAAE,iBAAiB,EAAE,MAAM,wBAAwB,CAAC;AAC3D,OAAO,EAAE,cAAc,EAAE,MAAM,qBAAqB,CAAC;AACrD,OAAO,EAAE,kBAAkB,EAAE,MAAM,yBAAyB,CAAC;AAC7D,OAAO,EAAE,sBAAsB,EAAE,MAAM,6BAA6B,CAAC;AACrE,OAAO,EAAE,mBAAmB,EAAE,MAAM,0BAA0B,CAAC;AAC/D,OAAO,EAAE,iBAAiB,EAAE,MAAM,wBAAwB,CAAC"}
@@ -7,7 +7,7 @@ export { SortableSidebarItem } from './SortableSidebarItem.js';
7
7
  export { stopSortableDragPointerDown } from './stopSortableDragPointerDown.js';
8
8
  export { SidebarColorDot } from './SidebarColorDot.js';
9
9
  export { SidebarBadge } from './SidebarBadge.js';
10
- export { sourceRow, METHOD_CLASSES, statusDotClass, SIDEBAR_ITEM_BUTTON_CLASS } from './sidebarItemClasses.js';
10
+ export { sourceRow, METHOD_CLASSES, statusDotVariant, statusDotClass, SIDEBAR_ITEM_BUTTON_CLASS } from './sidebarItemClasses.js';
11
11
  export { SidebarMethodBadge } from './SidebarMethodBadge.js';
12
12
  export { SidebarStatusDot } from './SidebarStatusDot.js';
13
13
  export { SidebarStatusMarker } from './SidebarStatusMarker.js';
@@ -1,3 +1,4 @@
1
+ import type { StatusDotVariant } from '../StatusDot/index.js';
1
2
  /**
2
3
  * Tailwind classes for sidebar source rows and HTTP method badges.
3
4
  */
@@ -13,6 +14,13 @@ export declare function sourceRow(selected: boolean, compact?: boolean): string;
13
14
  * HTTP method color classes keyed by lowercase method name.
14
15
  */
15
16
  export declare const METHOD_CLASSES: Record<string, string>;
17
+ /**
18
+ * Status dot variant for an HTTP response code.
19
+ *
20
+ * @param status - HTTP status code, or 0 for network errors.
21
+ * @returns Color preset for {@link StatusDot}.
22
+ */
23
+ export declare function statusDotVariant(status: number): StatusDotVariant;
16
24
  /**
17
25
  * Status dot color class for an HTTP response code.
18
26
  *
@@ -1 +1 @@
1
- {"version":3,"file":"sidebarItemClasses.d.ts","sourceRoot":"","sources":["../../../src/components/SidebarItem/sidebarItemClasses.ts"],"names":[],"mappings":"AAAA;;GAEG;AAEH;;;;;;GAMG;AACH,wBAAgB,SAAS,CAAC,QAAQ,EAAE,OAAO,EAAE,OAAO,UAAQ,GAAG,MAAM,CAKpE;AAED;;GAEG;AACH,eAAO,MAAM,cAAc,EAAE,MAAM,CAAC,MAAM,EAAE,MAAM,CAQjD,CAAC;AAEF;;;;;GAKG;AACH,wBAAgB,cAAc,CAAC,MAAM,EAAE,MAAM,GAAG,MAAM,CAMrD;AAED;;GAEG;AACH,eAAO,MAAM,yBAAyB,+HACwF,CAAC;AAE/H;;GAEG;AACH,eAAO,MAAM,yBAAyB,oVAC6S,CAAC"}
1
+ {"version":3,"file":"sidebarItemClasses.d.ts","sourceRoot":"","sources":["../../../src/components/SidebarItem/sidebarItemClasses.ts"],"names":[],"mappings":"AAAA,OAAO,KAAK,EAAE,gBAAgB,EAAE,MAAM,uBAAuB,CAAC;AAG9D;;GAEG;AAEH;;;;;;GAMG;AACH,wBAAgB,SAAS,CAAC,QAAQ,EAAE,OAAO,EAAE,OAAO,UAAQ,GAAG,MAAM,CAKpE;AAED;;GAEG;AACH,eAAO,MAAM,cAAc,EAAE,MAAM,CAAC,MAAM,EAAE,MAAM,CAQjD,CAAC;AAEF;;;;;GAKG;AACH,wBAAgB,gBAAgB,CAAC,MAAM,EAAE,MAAM,GAAG,gBAAgB,CAMjE;AAED;;;;;GAKG;AACH,wBAAgB,cAAc,CAAC,MAAM,EAAE,MAAM,GAAG,MAAM,CAErD;AAED;;GAEG;AACH,eAAO,MAAM,yBAAyB,+HACwF,CAAC;AAE/H;;GAEG;AACH,eAAO,MAAM,yBAAyB,oVAC6S,CAAC"}
@@ -1,3 +1,4 @@
1
+ import { statusDotVariantClass } from '../StatusDot/index.js';
1
2
  /**
2
3
  * Tailwind classes for sidebar source rows and HTTP method badges.
3
4
  */
@@ -27,21 +28,30 @@ export const METHOD_CLASSES = {
27
28
  options: 'text-method-options'
28
29
  };
29
30
  /**
30
- * Status dot color class for an HTTP response code.
31
+ * Status dot variant for an HTTP response code.
31
32
  *
32
33
  * @param status - HTTP status code, or 0 for network errors.
33
- * @returns Tailwind background color class for the status dot.
34
+ * @returns Color preset for {@link StatusDot}.
34
35
  */
35
- export function statusDotClass(status) {
36
+ export function statusDotVariant(status) {
36
37
  if (status === 0)
37
- return 'bg-danger';
38
+ return 'danger';
38
39
  if (status >= 200 && status < 300)
39
- return 'bg-success';
40
+ return 'success';
40
41
  if (status >= 300 && status < 400)
41
- return 'bg-warning';
42
+ return 'warning';
42
43
  if (status >= 400)
43
- return 'bg-danger';
44
- return 'bg-info';
44
+ return 'danger';
45
+ return 'info';
46
+ }
47
+ /**
48
+ * Status dot color class for an HTTP response code.
49
+ *
50
+ * @param status - HTTP status code, or 0 for network errors.
51
+ * @returns Tailwind background color class for the status dot.
52
+ */
53
+ export function statusDotClass(status) {
54
+ return statusDotVariantClass(statusDotVariant(status));
45
55
  }
46
56
  /**
47
57
  * Standard primary button classes for sidebar item label areas.
@@ -0,0 +1,42 @@
1
+ import type { ComponentPropsWithoutRef, JSX } from 'react';
2
+ /**
3
+ * Visual tone for compact circular status indicators.
4
+ */
5
+ export type StatusDotVariant = 'success' | 'danger' | 'muted' | 'accent' | 'warning' | 'info';
6
+ /**
7
+ * Size preset for the status dot.
8
+ */
9
+ export type StatusDotSize = 'sm' | 'md';
10
+ interface Props extends Omit<ComponentPropsWithoutRef<'span'>, 'children'> {
11
+ /**
12
+ * Color preset for the dot background.
13
+ */
14
+ variant?: StatusDotVariant;
15
+ /**
16
+ * Screen-reader text describing the status when a visible label is not shown.
17
+ */
18
+ label?: string;
19
+ /**
20
+ * Dot diameter preset. `md` is the default list-row size; `sm` fits compact
21
+ * footer indicators.
22
+ */
23
+ size?: StatusDotSize;
24
+ /**
25
+ * Native tooltip text for hover affordance.
26
+ */
27
+ title?: string;
28
+ }
29
+ /**
30
+ * Returns the Tailwind background class for the chosen status dot variant.
31
+ *
32
+ * @param variant - Color preset for the dot.
33
+ * @returns Tailwind background color class.
34
+ */
35
+ export declare function statusDotVariantClass(variant: StatusDotVariant): string;
36
+ /**
37
+ * Renders a small circular status indicator with optional screen-reader text.
38
+ * Use `label` when status is not conveyed by adjacent visible text.
39
+ */
40
+ export declare function StatusDot({ variant, label, size, title, className, ...props }: Props): JSX.Element;
41
+ export {};
42
+ //# sourceMappingURL=index.d.ts.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"index.d.ts","sourceRoot":"","sources":["../../../src/components/StatusDot/index.tsx"],"names":[],"mappings":"AAAA,OAAO,KAAK,EAAE,wBAAwB,EAAE,GAAG,EAAE,MAAM,OAAO,CAAC;AAG3D;;GAEG;AACH,MAAM,MAAM,gBAAgB,GAAG,SAAS,GAAG,QAAQ,GAAG,OAAO,GAAG,QAAQ,GAAG,SAAS,GAAG,MAAM,CAAC;AAE9F;;GAEG;AACH,MAAM,MAAM,aAAa,GAAG,IAAI,GAAG,IAAI,CAAC;AAExC,UAAU,KAAM,SAAQ,IAAI,CAAC,wBAAwB,CAAC,MAAM,CAAC,EAAE,UAAU,CAAC;IACxE;;OAEG;IACH,OAAO,CAAC,EAAE,gBAAgB,CAAC;IAE3B;;OAEG;IACH,KAAK,CAAC,EAAE,MAAM,CAAC;IAEf;;;OAGG;IACH,IAAI,CAAC,EAAE,aAAa,CAAC;IAErB;;OAEG;IACH,KAAK,CAAC,EAAE,MAAM,CAAC;CAChB;AAED;;;;;GAKG;AACH,wBAAgB,qBAAqB,CAAC,OAAO,EAAE,gBAAgB,GAAG,MAAM,CAgBvE;AAYD;;;GAGG;AACH,wBAAgB,SAAS,CAAC,EACxB,OAAiB,EACjB,KAAK,EACL,IAAW,EACX,KAAK,EACL,SAAS,EACT,GAAG,KAAK,EACT,EAAE,KAAK,GAAG,GAAG,CAAC,OAAO,CAgBrB"}
@@ -0,0 +1,42 @@
1
+ import { jsx as _jsx, jsxs as _jsxs } from "@harborclient/sdk/jsx-runtime";
2
+ import { cn } from '../utils.js';
3
+ /**
4
+ * Returns the Tailwind background class for the chosen status dot variant.
5
+ *
6
+ * @param variant - Color preset for the dot.
7
+ * @returns Tailwind background color class.
8
+ */
9
+ export function statusDotVariantClass(variant) {
10
+ switch (variant) {
11
+ case 'success':
12
+ return 'bg-success';
13
+ case 'danger':
14
+ return 'bg-danger';
15
+ case 'accent':
16
+ return 'bg-accent';
17
+ case 'warning':
18
+ return 'bg-warning';
19
+ case 'info':
20
+ return 'bg-info';
21
+ case 'muted':
22
+ default:
23
+ return 'bg-muted';
24
+ }
25
+ }
26
+ /**
27
+ * Returns Tailwind size classes for the chosen dot size preset.
28
+ *
29
+ * @param size - Dot diameter preset.
30
+ * @returns Tailwind width and height classes.
31
+ */
32
+ function sizeClasses(size) {
33
+ return size === 'sm' ? 'h-1.5 w-1.5' : 'h-2 w-2';
34
+ }
35
+ /**
36
+ * Renders a small circular status indicator with optional screen-reader text.
37
+ * Use `label` when status is not conveyed by adjacent visible text.
38
+ */
39
+ export function StatusDot({ variant = 'muted', label, size = 'md', title, className, ...props }) {
40
+ const hasLabel = label != null && label.length > 0;
41
+ return (_jsxs("span", { className: cn('inline-flex shrink-0 items-center', className), title: title, ...props, children: [_jsx("span", { className: cn('inline-block shrink-0 rounded-full', sizeClasses(size), statusDotVariantClass(variant)), "aria-hidden": "true" }), hasLabel ? _jsx("span", { className: "sr-only", children: label }) : null] }));
42
+ }
@@ -0,0 +1,71 @@
1
+ import type { JSX, ReactNode } from 'react';
2
+ /**
3
+ * One selectable theme variant shown in the picker.
4
+ */
5
+ export interface ThemeVariantOption {
6
+ /** Theme id within the plugin manifest. */
7
+ id: string;
8
+ /** Human-readable option label. */
9
+ label: string;
10
+ }
11
+ export interface Props {
12
+ /**
13
+ * Selectable theme variants contributed by the plugin.
14
+ */
15
+ variants: ThemeVariantOption[];
16
+ /**
17
+ * Whether variants are chosen from a dropdown or a radio fieldset.
18
+ */
19
+ selectionMode: 'select' | 'radio';
20
+ /**
21
+ * Dialog heading rendered in the modal header row.
22
+ */
23
+ title: ReactNode;
24
+ /**
25
+ * Body copy shown above the selector (or alone when the selector is hidden).
26
+ */
27
+ description: ReactNode;
28
+ /**
29
+ * Visible label for the selector control, or screen-reader legend text for radio mode.
30
+ */
31
+ selectorLabel?: string;
32
+ /**
33
+ * When false, hides the selector while still confirming the first variant.
34
+ */
35
+ showSelector?: boolean;
36
+ /**
37
+ * External in-flight flag from the parent (for example Redux-managed switching).
38
+ */
39
+ busy?: boolean;
40
+ /**
41
+ * Optional status text shown below the body while busy (select mode).
42
+ */
43
+ busyStatus?: ReactNode;
44
+ /**
45
+ * Primary action button label when idle.
46
+ */
47
+ confirmLabel: string;
48
+ /**
49
+ * Primary action button label while busy (radio mode).
50
+ */
51
+ busyConfirmLabel?: string;
52
+ /**
53
+ * Secondary dismiss button label.
54
+ */
55
+ cancelLabel: string;
56
+ /**
57
+ * Applies the selected variant and closes the dialog.
58
+ *
59
+ * @param themeId - Theme id within the plugin manifest.
60
+ */
61
+ onConfirm: (themeId: string) => void | Promise<void>;
62
+ /**
63
+ * Dismisses the picker without changing the active theme.
64
+ */
65
+ onCancel: () => void;
66
+ }
67
+ /**
68
+ * Modal that lets the user choose which theme variant to apply from a plugin.
69
+ */
70
+ export declare function ThemeVariantPickerModal({ variants, selectionMode, title, description, selectorLabel, showSelector, busy, busyStatus, confirmLabel, busyConfirmLabel, cancelLabel, onConfirm, onCancel }: Props): JSX.Element;
71
+ //# sourceMappingURL=index.d.ts.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"index.d.ts","sourceRoot":"","sources":["../../../src/components/ThemeVariantPickerModal/index.tsx"],"names":[],"mappings":"AACA,OAAO,KAAK,EAAE,GAAG,EAAE,SAAS,EAAE,MAAM,OAAO,CAAC;AAO5C;;GAEG;AACH,MAAM,WAAW,kBAAkB;IACjC,2CAA2C;IAC3C,EAAE,EAAE,MAAM,CAAC;IAEX,mCAAmC;IACnC,KAAK,EAAE,MAAM,CAAC;CACf;AAED,MAAM,WAAW,KAAK;IACpB;;OAEG;IACH,QAAQ,EAAE,kBAAkB,EAAE,CAAC;IAE/B;;OAEG;IACH,aAAa,EAAE,QAAQ,GAAG,OAAO,CAAC;IAElC;;OAEG;IACH,KAAK,EAAE,SAAS,CAAC;IAEjB;;OAEG;IACH,WAAW,EAAE,SAAS,CAAC;IAEvB;;OAEG;IACH,aAAa,CAAC,EAAE,MAAM,CAAC;IAEvB;;OAEG;IACH,YAAY,CAAC,EAAE,OAAO,CAAC;IAEvB;;OAEG;IACH,IAAI,CAAC,EAAE,OAAO,CAAC;IAEf;;OAEG;IACH,UAAU,CAAC,EAAE,SAAS,CAAC;IAEvB;;OAEG;IACH,YAAY,EAAE,MAAM,CAAC;IAErB;;OAEG;IACH,gBAAgB,CAAC,EAAE,MAAM,CAAC;IAE1B;;OAEG;IACH,WAAW,EAAE,MAAM,CAAC;IAEpB;;;;OAIG;IACH,SAAS,EAAE,CAAC,OAAO,EAAE,MAAM,KAAK,IAAI,GAAG,OAAO,CAAC,IAAI,CAAC,CAAC;IAErD;;OAEG;IACH,QAAQ,EAAE,MAAM,IAAI,CAAC;CACtB;AAED;;GAEG;AACH,wBAAgB,uBAAuB,CAAC,EACtC,QAAQ,EACR,aAAa,EACb,KAAK,EACL,WAAW,EACX,aAA+B,EAC/B,YAAmB,EACnB,IAAY,EACZ,UAAU,EACV,YAAY,EACZ,gBAAgB,EAChB,WAAW,EACX,SAAS,EACT,QAAQ,EACT,EAAE,KAAK,GAAG,GAAG,CAAC,OAAO,CAoFrB"}
@@ -0,0 +1,37 @@
1
+ import { jsx as _jsx, jsxs as _jsxs } from "@harborclient/sdk/jsx-runtime";
2
+ import { useCallback, useId, useState } from '@harborclient/sdk/react';
3
+ import { Button } from '../Button/index.js';
4
+ import { FormGroup } from '../FormGroup/index.js';
5
+ import { Modal, ModalFooter } from '../Modal/index.js';
6
+ import { StatusMessage } from '../StatusMessage/index.js';
7
+ import { Radio, Select } from '../forms/index.js';
8
+ /**
9
+ * Modal that lets the user choose which theme variant to apply from a plugin.
10
+ */
11
+ export function ThemeVariantPickerModal({ variants, selectionMode, title, description, selectorLabel = 'Theme variant', showSelector = true, busy = false, busyStatus, confirmLabel, busyConfirmLabel, cancelLabel, onConfirm, onCancel }) {
12
+ const titleId = useId();
13
+ const selectId = useId();
14
+ const radioGroupName = useId();
15
+ const [selectedThemeId, setSelectedThemeId] = useState(variants[0]?.id ?? '');
16
+ const [internalBusy, setInternalBusy] = useState(false);
17
+ const effectiveBusy = busy || internalBusy;
18
+ const primaryLabel = effectiveBusy && busyConfirmLabel ? busyConfirmLabel : confirmLabel;
19
+ /**
20
+ * Applies the selected variant and closes the dialog.
21
+ */
22
+ const handleConfirm = useCallback(() => {
23
+ if (!selectedThemeId) {
24
+ return;
25
+ }
26
+ setInternalBusy(true);
27
+ void (async () => {
28
+ try {
29
+ await onConfirm(selectedThemeId);
30
+ }
31
+ finally {
32
+ setInternalBusy(false);
33
+ }
34
+ })();
35
+ }, [onConfirm, selectedThemeId]);
36
+ return (_jsxs(Modal, { onClose: onCancel, labelledBy: titleId, title: title, closeDisabled: effectiveBusy, disableEscape: effectiveBusy, children: [_jsx("p", { className: "mb-3 text-[14px] text-muted", children: description }), showSelector && selectionMode === 'select' ? (_jsx(FormGroup, { label: selectorLabel, htmlFor: selectId, children: _jsx(Select, { id: selectId, value: selectedThemeId, disabled: effectiveBusy || variants.length === 0, onChange: (event) => setSelectedThemeId(event.target.value), children: variants.map((variant) => (_jsx("option", { value: variant.id, children: variant.label }, variant.id))) }) })) : null, showSelector && selectionMode === 'radio' ? (_jsxs("fieldset", { className: "m-0 space-y-2 border-none p-0", children: [_jsx("legend", { className: "sr-only", children: selectorLabel }), variants.map((variant) => (_jsx(FormGroup, { label: variant.label, layout: "checkbox", children: _jsx(Radio, { name: radioGroupName, checked: selectedThemeId === variant.id, onChange: () => setSelectedThemeId(variant.id), disabled: effectiveBusy }) }, variant.id)))] })) : null, effectiveBusy && busyStatus ? (_jsx(StatusMessage, { className: "mt-3", children: busyStatus })) : null, _jsxs(ModalFooter, { children: [_jsx(Button, { type: "button", variant: "secondary", disabled: effectiveBusy, onClick: onCancel, children: cancelLabel }), _jsx(Button, { type: "button", variant: "primary", disabled: effectiveBusy || !selectedThemeId, onClick: handleConfirm, children: primaryLabel })] })] }));
37
+ }