pixelize-design-library 2.4.2-beta.58 → 2.4.2-beta.60
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/CHANGELOG.md +149 -5
- package/COMPONENT-GOTCHAS.md +205 -18
- package/DESIGN-GUIDE.md +43 -9
- package/dist/Components/AppSwitcher/AppSwitcher.js +5 -1
- package/dist/Components/AppSwitcher/AppSwitcherProps.d.ts +2 -0
- package/dist/Components/AppSwitcher/AppSwitcherProps.js +7 -4
- package/dist/Components/AudioRecorder/AudioRecorder.d.ts +8 -0
- package/dist/Components/AudioRecorder/AudioRecorder.js +169 -0
- package/dist/Components/AudioRecorder/AudioRecorderProps.d.ts +20 -0
- package/dist/Components/AudioRecorder/AudioRecorderProps.js +2 -0
- package/dist/Components/Breadcrumbs/Breadcrumbs.d.ts +1 -1
- package/dist/Components/Breadcrumbs/Breadcrumbs.js +33 -10
- package/dist/Components/Breadcrumbs/BreadcrumbsProps.d.ts +16 -2
- package/dist/Components/BulkSelectionBar/BulkSelectionBar.d.ts +3 -0
- package/dist/Components/BulkSelectionBar/BulkSelectionBar.js +43 -0
- package/dist/Components/BulkSelectionBar/BulkSelectionBarProps.d.ts +35 -0
- package/dist/Components/BulkSelectionBar/BulkSelectionBarProps.js +2 -0
- package/dist/Components/BulkSelectionBar/index.d.ts +2 -0
- package/dist/Components/BulkSelectionBar/index.js +8 -0
- package/dist/Components/CalendarGrid/CalendarGrid.d.ts +3 -0
- package/dist/Components/CalendarGrid/CalendarGrid.js +173 -0
- package/dist/Components/CalendarGrid/CalendarGridProps.d.ts +54 -0
- package/dist/Components/CalendarGrid/CalendarGridProps.js +2 -0
- package/dist/Components/CalendarGrid/calendarMath.d.ts +49 -0
- package/dist/Components/CalendarGrid/calendarMath.js +178 -0
- package/dist/Components/Card/Card.d.ts +3 -1
- package/dist/Components/Card/Card.js +12 -2
- package/dist/Components/Card/CardProps.d.ts +5 -1
- package/dist/Components/CircularProgress/CircularProgress.d.ts +4 -0
- package/dist/Components/CircularProgress/CircularProgress.js +39 -0
- package/dist/Components/CircularProgress/CircularProgressProps.d.ts +22 -0
- package/dist/Components/CircularProgress/CircularProgressProps.js +2 -0
- package/dist/Components/CircularProgress/arc.d.ts +12 -0
- package/dist/Components/CircularProgress/arc.js +16 -0
- package/dist/Components/Common/fieldStyles.d.ts +1 -0
- package/dist/Components/Common/fieldStyles.js +2 -1
- package/dist/Components/Drawer/Drawer.d.ts +1 -1
- package/dist/Components/Drawer/Drawer.js +4 -2
- package/dist/Components/Drawer/DrawerProps.d.ts +3 -1
- package/dist/Components/Editor/Editor.js +50 -2
- package/dist/Components/Editor/EditorFieldBar.d.ts +15 -0
- package/dist/Components/Editor/EditorFieldBar.js +19 -0
- package/dist/Components/Editor/EditorProps.d.ts +74 -1
- package/dist/Components/Editor/MakeDynamicDialog.d.ts +12 -0
- package/dist/Components/Editor/MakeDynamicDialog.js +59 -0
- package/dist/Components/Editor/editorLabels.d.ts +4 -0
- package/dist/Components/Editor/editorLabels.js +24 -0
- package/dist/Components/Editor/editorTokenStyles.d.ts +28 -0
- package/dist/Components/Editor/editorTokenStyles.js +30 -0
- package/dist/Components/Editor/editorTokens.d.ts +26 -0
- package/dist/Components/Editor/editorTokens.js +134 -0
- package/dist/Components/Editor/useEditorBridge.d.ts +40 -0
- package/dist/Components/Editor/useEditorBridge.js +141 -0
- package/dist/Components/EmptyState/EmptyState.js +2 -1
- package/dist/Components/EmptyState/EmptyStateProps.d.ts +2 -2
- package/dist/Components/FormDrawer/FormDrawer.d.ts +2 -0
- package/dist/Components/FormDrawer/FormDrawer.js +97 -0
- package/dist/Components/FormDrawer/FormDrawerProps.d.ts +55 -0
- package/dist/Components/FormDrawer/FormDrawerProps.js +2 -0
- package/dist/Components/Kbd/Kbd.d.ts +6 -0
- package/dist/Components/Kbd/Kbd.js +33 -0
- package/dist/Components/Kbd/KbdProps.d.ts +17 -0
- package/dist/Components/Kbd/KbdProps.js +2 -0
- package/dist/Components/LauncherTrigger/LauncherTrigger.d.ts +4 -0
- package/dist/Components/LauncherTrigger/LauncherTrigger.js +48 -0
- package/dist/Components/LauncherTrigger/LauncherTriggerProps.d.ts +18 -0
- package/dist/Components/LauncherTrigger/LauncherTriggerProps.js +2 -0
- package/dist/Components/Modal/Modal.d.ts +1 -1
- package/dist/Components/Modal/Modal.js +4 -2
- package/dist/Components/Modal/ModalProps.d.ts +3 -1
- package/dist/Components/Modal/warnDroppedSlotChildren.d.ts +2 -0
- package/dist/Components/Modal/warnDroppedSlotChildren.js +45 -0
- package/dist/Components/NavLauncher/NavLauncher.d.ts +3 -0
- package/dist/Components/NavLauncher/NavLauncher.js +452 -0
- package/dist/Components/NavLauncher/NavLauncherProps.d.ts +187 -0
- package/dist/Components/NavLauncher/NavLauncherProps.js +2 -0
- package/dist/Components/NavLauncher/NewTabLink.d.ts +3 -0
- package/dist/Components/NavLauncher/NewTabLink.js +14 -0
- package/dist/Components/NavLauncher/PinToggle.d.ts +3 -0
- package/dist/Components/NavLauncher/PinToggle.js +21 -0
- package/dist/Components/NavLauncher/launcherParts.d.ts +152 -0
- package/dist/Components/NavLauncher/launcherParts.js +212 -0
- package/dist/Components/NavLauncher/match.d.ts +53 -0
- package/dist/Components/NavLauncher/match.js +178 -0
- package/dist/Components/NavLauncher/revealStyles.d.ts +4 -0
- package/dist/Components/NavLauncher/revealStyles.js +19 -0
- package/dist/Components/NavigationBar/NavigationBar.d.ts +1 -1
- package/dist/Components/NavigationBar/NavigationBar.js +2 -2
- package/dist/Components/NavigationBar/NavigationBarProps.d.ts +2 -0
- package/dist/Components/PageHeader/PageHeader.d.ts +1 -1
- package/dist/Components/PageHeader/PageHeader.js +9 -2
- package/dist/Components/PageHeader/PageHeaderProps.d.ts +8 -0
- package/dist/Components/PdfViewer/PdfViewer.d.ts +21 -4
- package/dist/Components/PdfViewer/PdfViewer.js +124 -3
- package/dist/Components/ProfilePhotoViewer/ProfilePhotoViewer.js +5 -0
- package/dist/Components/ProfilePhotoViewer/ProfilePhotoViewerProps.d.ts +1 -1
- package/dist/Components/QueryState/QueryStateBoundary.d.ts +2 -2
- package/dist/Components/QueryState/QueryStateBoundary.js +9 -3
- package/dist/Components/QueryState/QueryStateProps.d.ts +19 -2
- package/dist/Components/Search/Search.js +2 -1
- package/dist/Components/SectionRail/SectionRail.d.ts +3 -0
- package/dist/Components/SectionRail/SectionRail.js +49 -0
- package/dist/Components/SectionRail/SectionRailProps.d.ts +23 -0
- package/dist/Components/SectionRail/SectionRailProps.js +2 -0
- package/dist/Components/SectionRail/index.d.ts +2 -0
- package/dist/Components/SectionRail/index.js +8 -0
- package/dist/Components/SegmentedControl/SegmentedControl.js +9 -14
- package/dist/Components/SegmentedControl/segmentedInk.d.ts +0 -2
- package/dist/Components/SegmentedControl/segmentedInk.js +1 -5
- package/dist/Components/SideBar/SecondaryBar.js +4 -3
- package/dist/Components/SideBar/SideBar.d.ts +1 -1
- package/dist/Components/SideBar/SideBar.js +30 -9
- package/dist/Components/SideBar/SideBarProps.d.ts +32 -0
- package/dist/Components/SideBar/components/MenuItemBox.d.ts +6 -0
- package/dist/Components/SideBar/components/MenuItemBox.js +8 -4
- package/dist/Components/SideBar/components/MenuPopoverContent.js +3 -2
- package/dist/Components/SideBar/components/OtherApps.js +2 -1
- package/dist/Components/SideBar/components/PinnedSection.d.ts +17 -0
- package/dist/Components/SideBar/components/PinnedSection.js +98 -0
- package/dist/Components/SideBar/sidebarFocus.d.ts +23 -0
- package/dist/Components/SideBar/sidebarFocus.js +20 -0
- package/dist/Components/StageProgress/StageProgress.js +2 -2
- package/dist/Components/StageProgress/StageProgressProps.d.ts +2 -0
- package/dist/Components/StageProgress/StepperStage.js +5 -2
- package/dist/Components/StatCard/StatCard.d.ts +1 -1
- package/dist/Components/StatCard/StatCard.js +6 -2
- package/dist/Components/StatCard/StatCardProps.d.ts +3 -0
- package/dist/Components/StatusTag/StatusTag.d.ts +4 -0
- package/dist/Components/StatusTag/StatusTag.js +24 -0
- package/dist/Components/StatusTag/StatusTagProps.d.ts +20 -0
- package/dist/Components/StatusTag/StatusTagProps.js +2 -0
- package/dist/Components/Table/Table.d.ts +1 -1
- package/dist/Components/Table/Table.js +6 -2
- package/dist/Components/Table/TableProps.d.ts +20 -0
- package/dist/Components/Table/components/TableBody.d.ts +1 -1
- package/dist/Components/Table/components/TableBody.js +43 -18
- package/dist/Components/Table/components/TableHeader.d.ts +1 -1
- package/dist/Components/Table/components/TableHeader.js +7 -5
- package/dist/Components/Table/components/rowDetail.d.ts +32 -0
- package/dist/Components/Table/components/rowDetail.js +20 -0
- package/dist/Components/Table/hooks/useRowExpansion.d.ts +7 -0
- package/dist/Components/Table/hooks/useRowExpansion.js +27 -0
- package/dist/Components/Tabs/Tabs.d.ts +1 -1
- package/dist/Components/Tabs/Tabs.js +15 -2
- package/dist/Components/Tabs/TabsProps.d.ts +6 -2
- package/dist/Components/Tabs/components/Tab.js +4 -33
- package/dist/Components/Tabs/components/TabLinkList.d.ts +7 -0
- package/dist/Components/Tabs/components/TabLinkList.js +34 -0
- package/dist/Components/Tabs/useTabAppearance.d.ts +17 -0
- package/dist/Components/Tabs/useTabAppearance.js +67 -0
- package/dist/Components/Tag/Tag.js +11 -1
- package/dist/Components/Tag/TagProps.d.ts +4 -0
- package/dist/Components/Tag/tagDot.d.ts +3 -0
- package/dist/Components/Tag/tagDot.js +21 -0
- package/dist/Components/WizardDialog/WizardDialog.d.ts +9 -0
- package/dist/Components/WizardDialog/WizardDialog.js +102 -0
- package/dist/Components/WizardDialog/WizardDialogProps.d.ts +48 -0
- package/dist/Components/WizardDialog/WizardDialogProps.js +2 -0
- package/dist/Components/WizardDialog/useWizardFlow.d.ts +22 -0
- package/dist/Components/WizardDialog/useWizardFlow.js +47 -0
- package/dist/Components/WizardDialog/wizardSteps.d.ts +31 -0
- package/dist/Components/WizardDialog/wizardSteps.js +40 -0
- package/dist/esm/Components/AppSwitcher/AppSwitcher.js +2 -1
- package/dist/esm/Components/AppSwitcher/AppSwitcherProps.js +5 -3
- package/dist/esm/Components/AudioRecorder/AudioRecorder.js +161 -0
- package/dist/esm/Components/AudioRecorder/AudioRecorderProps.js +1 -0
- package/dist/esm/Components/Breadcrumbs/Breadcrumbs.js +35 -12
- package/dist/esm/Components/BulkSelectionBar/BulkSelectionBar.js +38 -0
- package/dist/esm/Components/BulkSelectionBar/BulkSelectionBarProps.js +1 -0
- package/dist/esm/Components/BulkSelectionBar/index.js +1 -0
- package/dist/esm/Components/CalendarGrid/CalendarGrid.js +168 -0
- package/dist/esm/Components/CalendarGrid/CalendarGridProps.js +1 -0
- package/dist/esm/Components/CalendarGrid/calendarMath.js +155 -0
- package/dist/esm/Components/Card/Card.js +12 -2
- package/dist/esm/Components/CircularProgress/CircularProgress.js +37 -0
- package/dist/esm/Components/CircularProgress/CircularProgressProps.js +1 -0
- package/dist/esm/Components/CircularProgress/arc.js +11 -0
- package/dist/esm/Components/Common/fieldStyles.js +2 -1
- package/dist/esm/Components/Drawer/Drawer.js +4 -2
- package/dist/esm/Components/Editor/Editor.js +48 -3
- package/dist/esm/Components/Editor/EditorFieldBar.js +13 -0
- package/dist/esm/Components/Editor/MakeDynamicDialog.js +20 -0
- package/dist/esm/Components/Editor/editorLabels.js +20 -0
- package/dist/esm/Components/Editor/editorTokenStyles.js +25 -0
- package/dist/esm/Components/Editor/editorTokens.js +121 -0
- package/dist/esm/Components/Editor/useEditorBridge.js +138 -0
- package/dist/esm/Components/EmptyState/EmptyState.js +2 -1
- package/dist/esm/Components/FormDrawer/FormDrawer.js +58 -0
- package/dist/esm/Components/FormDrawer/FormDrawerProps.js +1 -0
- package/dist/esm/Components/Kbd/Kbd.js +28 -0
- package/dist/esm/Components/Kbd/KbdProps.js +1 -0
- package/dist/esm/Components/LauncherTrigger/LauncherTrigger.js +41 -0
- package/dist/esm/Components/LauncherTrigger/LauncherTriggerProps.js +1 -0
- package/dist/esm/Components/Modal/Modal.js +4 -2
- package/dist/esm/Components/Modal/warnDroppedSlotChildren.js +38 -0
- package/dist/esm/Components/NavLauncher/NavLauncher.js +413 -0
- package/dist/esm/Components/NavLauncher/NavLauncherProps.js +1 -0
- package/dist/esm/Components/NavLauncher/NewTabLink.js +11 -0
- package/dist/esm/Components/NavLauncher/PinToggle.js +18 -0
- package/dist/esm/Components/NavLauncher/launcherParts.js +187 -0
- package/dist/esm/Components/NavLauncher/match.js +172 -0
- package/dist/esm/Components/NavLauncher/revealStyles.js +15 -0
- package/dist/esm/Components/NavigationBar/NavigationBar.js +3 -3
- package/dist/esm/Components/PageHeader/PageHeader.js +9 -2
- package/dist/esm/Components/PdfViewer/PdfViewer.js +123 -2
- package/dist/esm/Components/ProfilePhotoViewer/ProfilePhotoViewer.js +5 -0
- package/dist/esm/Components/QueryState/QueryStateBoundary.js +10 -4
- package/dist/esm/Components/Search/Search.js +3 -2
- package/dist/esm/Components/SectionRail/SectionRail.js +44 -0
- package/dist/esm/Components/SectionRail/SectionRailProps.js +1 -0
- package/dist/esm/Components/SectionRail/index.js +1 -0
- package/dist/esm/Components/SegmentedControl/SegmentedControl.js +11 -16
- package/dist/esm/Components/SegmentedControl/segmentedInk.js +0 -3
- package/dist/esm/Components/SideBar/SecondaryBar.js +4 -3
- package/dist/esm/Components/SideBar/SideBar.js +31 -10
- package/dist/esm/Components/SideBar/components/MenuItemBox.js +4 -2
- package/dist/esm/Components/SideBar/components/MenuPopoverContent.js +3 -2
- package/dist/esm/Components/SideBar/components/OtherApps.js +2 -1
- package/dist/esm/Components/SideBar/components/PinnedSection.js +92 -0
- package/dist/esm/Components/SideBar/sidebarFocus.js +15 -0
- package/dist/esm/Components/StageProgress/StageProgress.js +2 -2
- package/dist/esm/Components/StageProgress/StepperStage.js +5 -2
- package/dist/esm/Components/StatCard/StatCard.js +6 -2
- package/dist/esm/Components/StatusTag/StatusTag.js +19 -0
- package/dist/esm/Components/StatusTag/StatusTagProps.js +1 -0
- package/dist/esm/Components/Table/Table.js +7 -3
- package/dist/esm/Components/Table/components/TableBody.js +43 -18
- package/dist/esm/Components/Table/components/TableHeader.js +7 -5
- package/dist/esm/Components/Table/components/rowDetail.js +14 -0
- package/dist/esm/Components/Table/hooks/useRowExpansion.js +23 -0
- package/dist/esm/Components/Tabs/Tabs.js +15 -2
- package/dist/esm/Components/Tabs/components/Tab.js +4 -33
- package/dist/esm/Components/Tabs/components/TabLinkList.js +29 -0
- package/dist/esm/Components/Tabs/useTabAppearance.js +63 -0
- package/dist/esm/Components/Tag/Tag.js +12 -2
- package/dist/esm/Components/Tag/tagDot.js +17 -0
- package/dist/esm/Components/WizardDialog/WizardDialog.js +58 -0
- package/dist/esm/Components/WizardDialog/WizardDialogProps.js +1 -0
- package/dist/esm/Components/WizardDialog/useWizardFlow.js +44 -0
- package/dist/esm/Components/WizardDialog/wizardSteps.js +35 -0
- package/dist/esm/index.js +14 -0
- package/dist/index.d.ts +35 -6
- package/dist/index.js +38 -4
- package/package.json +1 -1
|
@@ -8,7 +8,8 @@ const outlineRung_1 = require("../../Theme/tokens/builders/outlineRung");
|
|
|
8
8
|
const focusRing_styles_1 = require("../../Theme/chakra/focusRing.styles");
|
|
9
9
|
exports.FIELD_RADIUS = "lg";
|
|
10
10
|
exports.FIELD_BORDER_WIDTH = "1px";
|
|
11
|
-
|
|
11
|
+
/** No box-shadow: the focus ring must be present the frame focus lands, not fade in. */
|
|
12
|
+
exports.FIELD_TRANSITION = (0, motion_1.transitionFor)(["border-color", "background-color"]);
|
|
12
13
|
/** Chakra `h`/`fontSize`/`px` for a field or select of this size. */
|
|
13
14
|
const controlSizeStyles = (size) => {
|
|
14
15
|
const spec = controlSizes_1.CONTROL_SIZES[size];
|
|
@@ -3,4 +3,4 @@ import { DrawerProps, DrawerHeaderSlotProps, DrawerBodySlotProps, DrawerFooterSl
|
|
|
3
3
|
export declare const DrawerHeader: React.FC<DrawerHeaderSlotProps>;
|
|
4
4
|
export declare const DrawerBody: React.FC<DrawerBodySlotProps>;
|
|
5
5
|
export declare const DrawerFooter: React.FC<DrawerFooterSlotProps>;
|
|
6
|
-
export default function Drawer({ isOpen, onClose, placement, size, id, variant, vaiant, initialFocusRef, finalFocusRef, closeOnOverlayClick, closeOnEsc, contentProps, hideCloseButton, children, }: DrawerProps): import("react/jsx-runtime").JSX.Element;
|
|
6
|
+
export default function Drawer({ isOpen, onClose, placement, size, id, variant, vaiant, initialFocusRef, finalFocusRef, closeOnOverlayClick, closeOnEsc, contentProps, hideCloseButton, portalChildren, children, }: DrawerProps): import("react/jsx-runtime").JSX.Element;
|
|
@@ -8,6 +8,7 @@ exports.default = Drawer;
|
|
|
8
8
|
const jsx_runtime_1 = require("react/jsx-runtime");
|
|
9
9
|
const react_1 = __importDefault(require("react"));
|
|
10
10
|
const useCustomTheme_1 = require("../../Theme/useCustomTheme");
|
|
11
|
+
const warnDroppedSlotChildren_1 = require("../Modal/warnDroppedSlotChildren");
|
|
11
12
|
const react_2 = require("@chakra-ui/react");
|
|
12
13
|
const DrawerHeader = ({ children }) => {
|
|
13
14
|
return (0, jsx_runtime_1.jsx)(jsx_runtime_1.Fragment, { children: children });
|
|
@@ -37,11 +38,12 @@ const findSlot = (children, slot) => {
|
|
|
37
38
|
}
|
|
38
39
|
return undefined;
|
|
39
40
|
};
|
|
40
|
-
function Drawer({ isOpen, onClose, placement = "right", size = "xl", id, variant, vaiant, initialFocusRef, finalFocusRef, closeOnOverlayClick, closeOnEsc, contentProps, hideCloseButton, children, }) {
|
|
41
|
+
function Drawer({ isOpen, onClose, placement = "right", size = "xl", id, variant, vaiant, initialFocusRef, finalFocusRef, closeOnOverlayClick, closeOnEsc, contentProps, hideCloseButton, portalChildren, children, }) {
|
|
41
42
|
var _a, _b;
|
|
42
43
|
const { colors } = (0, useCustomTheme_1.useCustomTheme)();
|
|
43
44
|
const headerSlot = findSlot(children, exports.DrawerHeader);
|
|
44
45
|
const bodySlot = findSlot(children, exports.DrawerBody);
|
|
45
46
|
const footerSlot = findSlot(children, exports.DrawerFooter);
|
|
46
|
-
|
|
47
|
+
(0, warnDroppedSlotChildren_1.warnDroppedSlotChildren)("Drawer", children, [exports.DrawerHeader, exports.DrawerBody, exports.DrawerFooter]);
|
|
48
|
+
return ((0, jsx_runtime_1.jsxs)(react_2.Drawer, { isOpen: isOpen, placement: placement, onClose: onClose, size: size, variant: (_a = variant !== null && variant !== void 0 ? variant : vaiant) !== null && _a !== void 0 ? _a : "solid", id: id, initialFocusRef: initialFocusRef, finalFocusRef: finalFocusRef, closeOnOverlayClick: closeOnOverlayClick, closeOnEsc: closeOnEsc, children: [(0, jsx_runtime_1.jsx)(react_2.DrawerOverlay, {}), (0, jsx_runtime_1.jsxs)(react_2.DrawerContent, { ...contentProps, children: [!hideCloseButton && (0, jsx_runtime_1.jsx)(react_2.DrawerCloseButton, {}), headerSlot && ((0, jsx_runtime_1.jsx)(react_2.DrawerHeader, { borderBottomWidth: "1px", borderColor: colors.boxborder[200], ...headerSlot.props, children: headerSlot })), (0, jsx_runtime_1.jsx)(react_2.DrawerBody, { ...((_b = bodySlot === null || bodySlot === void 0 ? void 0 : bodySlot.props) !== null && _b !== void 0 ? _b : {}), children: bodySlot }), footerSlot && ((0, jsx_runtime_1.jsx)(react_2.DrawerFooter, { borderTopWidth: "1px", borderColor: colors.boxborder[200], ...footerSlot.props, children: footerSlot })), portalChildren] })] }));
|
|
47
49
|
}
|
|
@@ -1,5 +1,5 @@
|
|
|
1
1
|
import { DrawerProps as ChakraDrawerProps, DrawerContentProps, ModalHeaderProps, ModalBodyProps, ModalFooterProps } from "@chakra-ui/react";
|
|
2
|
-
/** Only DrawerHeader/Body/Footer children render, matched by type one fragment deep; any other
|
|
2
|
+
/** Only DrawerHeader/Body/Footer children render, matched by type one fragment deep; any other child is dropped (dev console.warn) — use `portalChildren`. */
|
|
3
3
|
export type DrawerProps = Pick<ChakraDrawerProps, "isOpen" | "onClose" | "placement" | "size" | "id" | "variant" | "initialFocusRef" | "finalFocusRef" | "closeOnOverlayClick" | "closeOnEsc"> & {
|
|
4
4
|
/** Defaults to "xl". */
|
|
5
5
|
size?: "xs" | "sm" | "md" | "lg" | "xl" | "full";
|
|
@@ -12,6 +12,8 @@ export type DrawerProps = Pick<ChakraDrawerProps, "isOpen" | "onClose" | "placem
|
|
|
12
12
|
contentProps?: DrawerContentProps;
|
|
13
13
|
/** Drops the built-in close button, for a drawer dismissed only by its own footer action. */
|
|
14
14
|
hideCloseButton?: boolean;
|
|
15
|
+
/** Rendered inside the drawer's dialog after the slots (so live regions stay announced); nested dialogs portal out and keep focus here. Unmounts with the drawer. */
|
|
16
|
+
portalChildren?: React.ReactNode;
|
|
15
17
|
};
|
|
16
18
|
/** Chakra style props (padding, borderBottom, gap, sx, ...) spread onto the rendered DrawerHeader; omit to keep theme defaults. Chakra's Drawer reuses Modal's header part internally. */
|
|
17
19
|
export type DrawerHeaderSlotProps = ModalHeaderProps;
|
|
@@ -32,10 +32,23 @@ var __importStar = (this && this.__importStar) || (function () {
|
|
|
32
32
|
return result;
|
|
33
33
|
};
|
|
34
34
|
})();
|
|
35
|
+
var __importDefault = (this && this.__importDefault) || function (mod) {
|
|
36
|
+
return (mod && mod.__esModule) ? mod : { "default": mod };
|
|
37
|
+
};
|
|
35
38
|
Object.defineProperty(exports, "__esModule", { value: true });
|
|
36
39
|
const jsx_runtime_1 = require("react/jsx-runtime");
|
|
37
40
|
const react_1 = __importStar(require("react"));
|
|
38
41
|
const react_2 = require("@chakra-ui/react");
|
|
42
|
+
const FieldMessage_1 = __importDefault(require("../Common/FieldMessage"));
|
|
43
|
+
const ErrorMessage_1 = __importDefault(require("../Common/ErrorMessage"));
|
|
44
|
+
const FormLabel_1 = require("../Common/FormLabel");
|
|
45
|
+
const useFieldIds_1 = require("../Common/useFieldIds");
|
|
46
|
+
const EditorFieldBar_1 = __importDefault(require("./EditorFieldBar"));
|
|
47
|
+
const MakeDynamicDialog_1 = __importDefault(require("./MakeDynamicDialog"));
|
|
48
|
+
const editorTokens_1 = require("./editorTokens");
|
|
49
|
+
const editorTokenStyles_1 = require("./editorTokenStyles");
|
|
50
|
+
const editorLabels_1 = require("./editorLabels");
|
|
51
|
+
const useEditorBridge_1 = require("./useEditorBridge");
|
|
39
52
|
const useCustomTheme_1 = require("../../Theme/useCustomTheme");
|
|
40
53
|
const accentText_1 = require("../../Theme/tokens/builders/accentText");
|
|
41
54
|
const joditThemeVars_1 = require("./joditThemeVars");
|
|
@@ -48,8 +61,25 @@ const JoditEditor = react_1.default.lazy(async () => {
|
|
|
48
61
|
return { default: ((_a = mod.default) !== null && _a !== void 0 ? _a : mod) };
|
|
49
62
|
});
|
|
50
63
|
/** Lazy-loaded Jodit wrapper — a `config.theme` or `config.popupRoot` you pass overrides this library's own dark-mode/popup fix; omit both keys. */
|
|
51
|
-
const Editor = react_1.default.memo(function Editor({ value, key, config, editorRef, className, onChange, onBlur, }) {
|
|
64
|
+
const Editor = react_1.default.memo(function Editor({ value, key, config, editorRef, className, onChange, onBlur, label, isRequired, helperText, error, errorMessage, mergeFields, tokenSyntax = editorTokens_1.DEFAULT_TOKEN_SYNTAX, showMakeDynamic, toolbarButtons, onUnknownTokens, apiRef, onReady, labels, "data-testid": testId, }) {
|
|
52
65
|
const theme = (0, useCustomTheme_1.useCustomTheme)();
|
|
66
|
+
const text = (0, react_1.useMemo)(() => (0, editorLabels_1.resolveEditorLabels)(labels), [labels]);
|
|
67
|
+
const { joditValue, attachEditor, api, instance, unknown } = (0, useEditorBridge_1.useEditorBridge)({
|
|
68
|
+
value,
|
|
69
|
+
onChange,
|
|
70
|
+
onBlur,
|
|
71
|
+
mergeFields,
|
|
72
|
+
syntax: tokenSyntax,
|
|
73
|
+
chipLabel: text.fieldChip,
|
|
74
|
+
apiRef,
|
|
75
|
+
onReady,
|
|
76
|
+
onUnknownTokens,
|
|
77
|
+
});
|
|
78
|
+
const hasFields = mergeFields !== undefined;
|
|
79
|
+
const options = (0, react_1.useMemo)(() => (0, editorTokens_1.fieldOptions)(mergeFields !== null && mergeFields !== void 0 ? mergeFields : [], tokenSyntax),
|
|
80
|
+
// eslint-disable-next-line react-hooks/exhaustive-deps
|
|
81
|
+
[JSON.stringify(mergeFields), tokenSyntax.open, tokenSyntax.close]);
|
|
82
|
+
const [dynamicText, setDynamicText] = (0, react_1.useState)(null);
|
|
53
83
|
// Jodit portals dialogs/toolbar-dropdown popups (search & replace, image/link properties,
|
|
54
84
|
// font-size list, ...) to `document.body` by default (`Dialog.destination` /
|
|
55
85
|
// `getPopupViewRoot`), outside this wrapper's DOM subtree — so the CSS custom properties
|
|
@@ -84,6 +114,24 @@ const Editor = react_1.default.memo(function Editor({ value, key, config, editor
|
|
|
84
114
|
observer.observe(popupRoot, { childList: true, subtree: true });
|
|
85
115
|
return () => observer.disconnect();
|
|
86
116
|
}, [popupRoot]);
|
|
87
|
-
|
|
117
|
+
const unknownActive = hasFields && unknown.length > 0 && !(error && errorMessage);
|
|
118
|
+
const ids = (0, useFieldIds_1.useFieldIds)(undefined, { error, errorMessage, helperText });
|
|
119
|
+
const describedBy = unknownActive ? ids.errorId : ids.describedBy;
|
|
120
|
+
const invalid = Boolean(error) || unknownActive;
|
|
121
|
+
const isReadOnly = Boolean(stableConfig === null || stableConfig === void 0 ? void 0 : stableConfig.readonly);
|
|
122
|
+
(0, react_1.useEffect)(() => {
|
|
123
|
+
if (!instance)
|
|
124
|
+
return;
|
|
125
|
+
const el = instance.editor;
|
|
126
|
+
const set = (name, val) => val === undefined ? el.removeAttribute(name) : el.setAttribute(name, val);
|
|
127
|
+
set("role", "textbox");
|
|
128
|
+
set("aria-multiline", "true");
|
|
129
|
+
set("aria-labelledby", label ? ids.labelId : undefined);
|
|
130
|
+
set("aria-describedby", describedBy);
|
|
131
|
+
set("aria-invalid", invalid ? "true" : undefined);
|
|
132
|
+
set("aria-required", isRequired ? "true" : undefined);
|
|
133
|
+
}, [instance, label, ids.labelId, describedBy, invalid, isRequired]);
|
|
134
|
+
const showFieldBar = hasFields || Boolean(toolbarButtons === null || toolbarButtons === void 0 ? void 0 : toolbarButtons.length);
|
|
135
|
+
return ((0, jsx_runtime_1.jsxs)(react_2.Box, { "data-testid": testId, children: [label && ((0, jsx_runtime_1.jsxs)(react_2.Box, { as: "label", id: ids.labelId, display: "block", onClick: () => api.focus(), ...(0, FormLabel_1.fieldLabelStyles)(theme.colors), children: [label, isRequired && ((0, jsx_runtime_1.jsx)("span", { "aria-hidden": true, style: { color: theme.colors.semanticText.error, marginLeft: "0.125rem" }, children: "*" }))] })), showFieldBar && ((0, jsx_runtime_1.jsx)(EditorFieldBar_1.default, { options: options, labels: text, api: api, isDisabled: !instance || isReadOnly, showFieldMenu: hasFields, showMakeDynamic: hasFields && (showMakeDynamic !== null && showMakeDynamic !== void 0 ? showMakeDynamic : true), buttons: toolbarButtons !== null && toolbarButtons !== void 0 ? toolbarButtons : [], onMakeDynamic: () => setDynamicText(api.getSelectionText()) })), (0, jsx_runtime_1.jsx)(react_2.Box, { ref: setPopupRoot, sx: { ...themeVars, ...(0, editorTokenStyles_1.chipStyles)(theme.colors) }, children: (0, jsx_runtime_1.jsx)(react_1.Suspense, { fallback: null, children: popupRoot && ((0, jsx_runtime_1.jsx)(JoditEditor, { config: stableConfig, value: joditValue, ref: editorRef, editorRef: attachEditor, className: className }, key)) }) }), unknownActive ? ((0, jsx_runtime_1.jsx)(ErrorMessage_1.default, { id: ids.errorId, errorMessage: text.unknownTokens(unknown.join(", ")) })) : ((0, jsx_runtime_1.jsx)(FieldMessage_1.default, { error: error, errorMessage: errorMessage, helperText: helperText, helperId: ids.helperId, errorId: ids.errorId })), hasFields && ((0, jsx_runtime_1.jsx)(MakeDynamicDialog_1.default, { selectedText: dynamicText, options: options, labels: text, countFor: api.countOccurrences, onReplace: api.replaceAll, onClose: () => setDynamicText(null) }))] }));
|
|
88
136
|
});
|
|
89
137
|
exports.default = Editor;
|
|
@@ -0,0 +1,15 @@
|
|
|
1
|
+
import type { OptionProp } from "../Select/SelectProps";
|
|
2
|
+
import type { EditorApi, EditorToolbarButton } from "./EditorProps";
|
|
3
|
+
import type { ResolvedEditorLabels } from "./editorLabels";
|
|
4
|
+
type EditorFieldBarProps = {
|
|
5
|
+
options: OptionProp[];
|
|
6
|
+
labels: ResolvedEditorLabels;
|
|
7
|
+
api: EditorApi;
|
|
8
|
+
isDisabled: boolean;
|
|
9
|
+
showFieldMenu: boolean;
|
|
10
|
+
showMakeDynamic: boolean;
|
|
11
|
+
buttons: EditorToolbarButton[];
|
|
12
|
+
onMakeDynamic: () => void;
|
|
13
|
+
};
|
|
14
|
+
export default function EditorFieldBar({ options, labels, api, isDisabled, showFieldMenu, showMakeDynamic, buttons, onMakeDynamic, }: EditorFieldBarProps): import("react/jsx-runtime").JSX.Element;
|
|
15
|
+
export {};
|
|
@@ -0,0 +1,19 @@
|
|
|
1
|
+
"use strict";
|
|
2
|
+
var __importDefault = (this && this.__importDefault) || function (mod) {
|
|
3
|
+
return (mod && mod.__esModule) ? mod : { "default": mod };
|
|
4
|
+
};
|
|
5
|
+
Object.defineProperty(exports, "__esModule", { value: true });
|
|
6
|
+
exports.default = EditorFieldBar;
|
|
7
|
+
const jsx_runtime_1 = require("react/jsx-runtime");
|
|
8
|
+
const react_1 = require("@chakra-ui/react");
|
|
9
|
+
const lucide_react_1 = require("lucide-react");
|
|
10
|
+
const Button_1 = __importDefault(require("../Button/Button"));
|
|
11
|
+
const Select_1 = __importDefault(require("../Select/Select"));
|
|
12
|
+
function EditorFieldBar({ options, labels, api, isDisabled, showFieldMenu, showMakeDynamic, buttons, onMakeDynamic, }) {
|
|
13
|
+
return ((0, jsx_runtime_1.jsxs)(react_1.Flex, { role: "toolbar", "aria-label": labels.toolbar, gap: 2, wrap: "wrap", align: "center", mb: 2, children: [showFieldMenu && ((0, jsx_runtime_1.jsx)(react_1.Box, { width: { base: "100%", sm: "16rem" }, children: (0, jsx_runtime_1.jsx)(Select_1.default, { native: false, "aria-label": labels.insertField, placeholder: labels.insertField, options: options, value: "", noOptionsMessage: labels.noFields, isDisabled: isDisabled, onChange: (option) => {
|
|
14
|
+
if (!option)
|
|
15
|
+
return;
|
|
16
|
+
api.insertField(String(option.id));
|
|
17
|
+
window.setTimeout(api.focus, 0);
|
|
18
|
+
}, "data-testid": "editor-insert-field" }) })), showMakeDynamic && ((0, jsx_runtime_1.jsx)(Button_1.default, { variant: "outline", colorScheme: "gray", leftIcon: (0, jsx_runtime_1.jsx)(lucide_react_1.WandSparkles, { size: 16, "aria-hidden": true }), label: labels.makeDynamic, onClick: onMakeDynamic, isDisabled: isDisabled, "data-testid": "editor-make-dynamic" })), buttons.map((button) => ((0, jsx_runtime_1.jsx)(Button_1.default, { variant: "ghost", colorScheme: "gray", leftIcon: button.icon ? (0, jsx_runtime_1.jsx)(react_1.Icon, { as: button.icon, boxSize: 4, "aria-hidden": true }) : undefined, label: button.label, onClick: () => button.onClick(api), isDisabled: isDisabled || button.isDisabled, "data-testid": `editor-button-${button.id}` }, button.id)))] }));
|
|
19
|
+
}
|
|
@@ -1,10 +1,83 @@
|
|
|
1
1
|
import type JoditEditor from "jodit-react";
|
|
2
|
-
import type { ComponentProps } from "react";
|
|
2
|
+
import type { ComponentProps, ElementType, Ref } from "react";
|
|
3
3
|
type JoditEditorProps = ComponentProps<typeof JoditEditor>;
|
|
4
|
+
/** A field a template can reference; `path` is what the stored token carries. */
|
|
5
|
+
export type EditorMergeField = {
|
|
6
|
+
/** Dotted path the backend resolves, e.g. `candidate.name`. */
|
|
7
|
+
path: string;
|
|
8
|
+
label: string;
|
|
9
|
+
/** Heading the field is listed under in the Insert field menu. */
|
|
10
|
+
group?: string;
|
|
11
|
+
/** Example value, shown on the chip's hover title. */
|
|
12
|
+
sample?: string;
|
|
13
|
+
};
|
|
14
|
+
/** How a token is written in the stored HTML. */
|
|
15
|
+
export type EditorTokenSyntax = {
|
|
16
|
+
open: string;
|
|
17
|
+
close: string;
|
|
18
|
+
};
|
|
19
|
+
/** Imperative handle for toolbar buttons and `apiRef`; every method works on the live editor. */
|
|
20
|
+
export interface EditorApi {
|
|
21
|
+
insertHTML(html: string): void;
|
|
22
|
+
insertField(path: string): void;
|
|
23
|
+
getSelectionText(): string;
|
|
24
|
+
/** Replaces every plain-text occurrence outside tokens and tags; returns the count. */
|
|
25
|
+
replaceAll(text: string, path: string): number;
|
|
26
|
+
countOccurrences(text: string): number;
|
|
27
|
+
focus(): void;
|
|
28
|
+
}
|
|
29
|
+
/** An extra button in the strip above the editor. */
|
|
30
|
+
export type EditorToolbarButton = {
|
|
31
|
+
id: string;
|
|
32
|
+
label: string;
|
|
33
|
+
icon?: ElementType;
|
|
34
|
+
/** Read through a ref — a new function each render never re-creates the editor. */
|
|
35
|
+
onClick: (api: EditorApi) => void;
|
|
36
|
+
isDisabled?: boolean;
|
|
37
|
+
};
|
|
38
|
+
/** Every visible string of the merge-field UI; omit a key to keep its English default. */
|
|
39
|
+
export type EditorLabels = Partial<{
|
|
40
|
+
insertField: string;
|
|
41
|
+
noFields: string;
|
|
42
|
+
makeDynamic: string;
|
|
43
|
+
dynamicTitle: string;
|
|
44
|
+
dynamicField: string;
|
|
45
|
+
dynamicFieldPlaceholder: string;
|
|
46
|
+
dynamicCount: (n: number) => string;
|
|
47
|
+
dynamicReplace: string;
|
|
48
|
+
dynamicNoSelection: string;
|
|
49
|
+
unknownTokens: (list: string) => string;
|
|
50
|
+
cancel: string;
|
|
51
|
+
dynamicSelected: string;
|
|
52
|
+
toolbar: string;
|
|
53
|
+
fieldChip: (label: string) => string;
|
|
54
|
+
}>;
|
|
4
55
|
/** Props for the lazy-loaded Jodit wrapper; a `config.theme`/`config.popupRoot` you pass overrides this library's own dark-mode fix. */
|
|
5
56
|
export type EditorProps = Pick<JoditEditorProps, "value" | "config" | "className" | "onChange" | "onBlur"> & {
|
|
6
57
|
/** `key` is dead (React reserves it, never reaches Jodit); `editorRef.current` stays null until the lazy chunk loads. */
|
|
7
58
|
editorRef?: JoditEditorProps["ref"];
|
|
8
59
|
key?: string | number;
|
|
60
|
+
label?: string;
|
|
61
|
+
isRequired?: boolean;
|
|
62
|
+
/** Hint under the editor; replaced by `errorMessage` while `error` is true. */
|
|
63
|
+
helperText?: string;
|
|
64
|
+
/** Marks the editor invalid; `errorMessage` shows only while this is true. */
|
|
65
|
+
error?: boolean;
|
|
66
|
+
errorMessage?: string;
|
|
67
|
+
/** Enables the Insert field menu, token chips and Make dynamic. */
|
|
68
|
+
mergeFields?: EditorMergeField[];
|
|
69
|
+
/** Token syntax in the stored HTML; default `{ open: "${", close: "}" }`. */
|
|
70
|
+
tokenSyntax?: EditorTokenSyntax;
|
|
71
|
+
/** Shows the Make dynamic button; defaults to true when `mergeFields` is set. */
|
|
72
|
+
showMakeDynamic?: boolean;
|
|
73
|
+
/** Extra buttons beside Insert field; handlers are read through refs. */
|
|
74
|
+
toolbarButtons?: EditorToolbarButton[];
|
|
75
|
+
/** Fires with the paths of tokens that match no merge field, when that set changes. */
|
|
76
|
+
onUnknownTokens?: (paths: string[]) => void;
|
|
77
|
+
/** Imperative API, available after the lazy chunk loads (`onReady` fires then). */
|
|
78
|
+
apiRef?: Ref<EditorApi>;
|
|
79
|
+
onReady?: () => void;
|
|
80
|
+
labels?: EditorLabels;
|
|
81
|
+
"data-testid"?: string;
|
|
9
82
|
};
|
|
10
83
|
export {};
|
|
@@ -0,0 +1,12 @@
|
|
|
1
|
+
import type { OptionProp } from "../Select/SelectProps";
|
|
2
|
+
import type { ResolvedEditorLabels } from "./editorLabels";
|
|
3
|
+
type MakeDynamicDialogProps = {
|
|
4
|
+
selectedText: string | null;
|
|
5
|
+
options: OptionProp[];
|
|
6
|
+
labels: ResolvedEditorLabels;
|
|
7
|
+
countFor: (text: string) => number;
|
|
8
|
+
onReplace: (text: string, path: string) => void;
|
|
9
|
+
onClose: () => void;
|
|
10
|
+
};
|
|
11
|
+
export default function MakeDynamicDialog({ selectedText, options, labels, countFor, onReplace, onClose, }: MakeDynamicDialogProps): import("react/jsx-runtime").JSX.Element;
|
|
12
|
+
export {};
|
|
@@ -0,0 +1,59 @@
|
|
|
1
|
+
"use strict";
|
|
2
|
+
var __createBinding = (this && this.__createBinding) || (Object.create ? (function(o, m, k, k2) {
|
|
3
|
+
if (k2 === undefined) k2 = k;
|
|
4
|
+
var desc = Object.getOwnPropertyDescriptor(m, k);
|
|
5
|
+
if (!desc || ("get" in desc ? !m.__esModule : desc.writable || desc.configurable)) {
|
|
6
|
+
desc = { enumerable: true, get: function() { return m[k]; } };
|
|
7
|
+
}
|
|
8
|
+
Object.defineProperty(o, k2, desc);
|
|
9
|
+
}) : (function(o, m, k, k2) {
|
|
10
|
+
if (k2 === undefined) k2 = k;
|
|
11
|
+
o[k2] = m[k];
|
|
12
|
+
}));
|
|
13
|
+
var __setModuleDefault = (this && this.__setModuleDefault) || (Object.create ? (function(o, v) {
|
|
14
|
+
Object.defineProperty(o, "default", { enumerable: true, value: v });
|
|
15
|
+
}) : function(o, v) {
|
|
16
|
+
o["default"] = v;
|
|
17
|
+
});
|
|
18
|
+
var __importStar = (this && this.__importStar) || (function () {
|
|
19
|
+
var ownKeys = function(o) {
|
|
20
|
+
ownKeys = Object.getOwnPropertyNames || function (o) {
|
|
21
|
+
var ar = [];
|
|
22
|
+
for (var k in o) if (Object.prototype.hasOwnProperty.call(o, k)) ar[ar.length] = k;
|
|
23
|
+
return ar;
|
|
24
|
+
};
|
|
25
|
+
return ownKeys(o);
|
|
26
|
+
};
|
|
27
|
+
return function (mod) {
|
|
28
|
+
if (mod && mod.__esModule) return mod;
|
|
29
|
+
var result = {};
|
|
30
|
+
if (mod != null) for (var k = ownKeys(mod), i = 0; i < k.length; i++) if (k[i] !== "default") __createBinding(result, mod, k[i]);
|
|
31
|
+
__setModuleDefault(result, mod);
|
|
32
|
+
return result;
|
|
33
|
+
};
|
|
34
|
+
})();
|
|
35
|
+
var __importDefault = (this && this.__importDefault) || function (mod) {
|
|
36
|
+
return (mod && mod.__esModule) ? mod : { "default": mod };
|
|
37
|
+
};
|
|
38
|
+
Object.defineProperty(exports, "__esModule", { value: true });
|
|
39
|
+
exports.default = MakeDynamicDialog;
|
|
40
|
+
const jsx_runtime_1 = require("react/jsx-runtime");
|
|
41
|
+
const react_1 = require("react");
|
|
42
|
+
const react_2 = require("@chakra-ui/react");
|
|
43
|
+
const Button_1 = __importDefault(require("../Button/Button"));
|
|
44
|
+
const Modal_1 = __importStar(require("../Modal/Modal"));
|
|
45
|
+
const Select_1 = __importDefault(require("../Select/Select"));
|
|
46
|
+
const useCustomTheme_1 = require("../../Theme/useCustomTheme");
|
|
47
|
+
function MakeDynamicDialog({ selectedText, options, labels, countFor, onReplace, onClose, }) {
|
|
48
|
+
const { colors } = (0, useCustomTheme_1.useCustomTheme)();
|
|
49
|
+
const [path, setPath] = (0, react_1.useState)("");
|
|
50
|
+
const count = selectedText ? countFor(selectedText) : 0;
|
|
51
|
+
const close = () => {
|
|
52
|
+
setPath("");
|
|
53
|
+
onClose();
|
|
54
|
+
};
|
|
55
|
+
return ((0, jsx_runtime_1.jsxs)(Modal_1.default, { isOpen: selectedText !== null, onClose: close, size: "md", isCentered: true, title: labels.dynamicTitle, children: [(0, jsx_runtime_1.jsx)(Modal_1.ModalBody, { children: selectedText ? ((0, jsx_runtime_1.jsxs)(react_2.Flex, { direction: "column", gap: 4, "data-testid": "editor-dynamic-dialog", children: [(0, jsx_runtime_1.jsxs)(react_2.Box, { children: [(0, jsx_runtime_1.jsx)(react_2.Text, { fontSize: "xs", color: colors.textMuted, children: labels.dynamicSelected }), (0, jsx_runtime_1.jsxs)(react_2.Text, { fontSize: "sm", fontWeight: 500, color: colors.text[800], noOfLines: 3, children: ["\u201C", selectedText, "\u201D"] })] }), (0, jsx_runtime_1.jsx)(Select_1.default, { native: false, label: labels.dynamicField, placeholder: labels.dynamicFieldPlaceholder, options: options, value: path, onChange: (option) => setPath(option ? String(option.id) : ""), "data-testid": "editor-dynamic-field" }), (0, jsx_runtime_1.jsx)(react_2.Text, { fontSize: "sm", color: colors.textMuted, "aria-live": "polite", children: labels.dynamicCount(count) })] })) : ((0, jsx_runtime_1.jsx)(react_2.Text, { fontSize: "sm", color: colors.text[800], "data-testid": "editor-dynamic-empty", children: labels.dynamicNoSelection })) }), (0, jsx_runtime_1.jsx)(Modal_1.ModalFooter, { children: (0, jsx_runtime_1.jsxs)(react_2.Flex, { gap: 2, justify: "flex-end", w: "100%", children: [(0, jsx_runtime_1.jsx)(Button_1.default, { variant: "ghost", colorScheme: "gray", label: labels.cancel, onClick: close }), selectedText ? ((0, jsx_runtime_1.jsx)(Button_1.default, { variant: "solid", colorScheme: "primary", label: labels.dynamicReplace, onClick: () => {
|
|
56
|
+
onReplace(selectedText, path);
|
|
57
|
+
close();
|
|
58
|
+
}, isDisabled: !path || count === 0, "data-testid": "editor-dynamic-apply" })) : null] }) })] }));
|
|
59
|
+
}
|
|
@@ -0,0 +1,24 @@
|
|
|
1
|
+
"use strict";
|
|
2
|
+
Object.defineProperty(exports, "__esModule", { value: true });
|
|
3
|
+
exports.resolveEditorLabels = exports.DEFAULT_EDITOR_LABELS = void 0;
|
|
4
|
+
exports.DEFAULT_EDITOR_LABELS = {
|
|
5
|
+
insertField: "Insert field",
|
|
6
|
+
noFields: "No fields",
|
|
7
|
+
makeDynamic: "Make dynamic",
|
|
8
|
+
dynamicTitle: "Make dynamic",
|
|
9
|
+
dynamicField: "Field",
|
|
10
|
+
dynamicFieldPlaceholder: "Choose a field",
|
|
11
|
+
dynamicCount: (n) => `${n} ${n === 1 ? "occurrence" : "occurrences"} will be replaced`,
|
|
12
|
+
dynamicReplace: "Replace",
|
|
13
|
+
dynamicNoSelection: "Select some text in the editor first.",
|
|
14
|
+
unknownTokens: (list) => `Unknown fields: ${list}`,
|
|
15
|
+
cancel: "Cancel",
|
|
16
|
+
dynamicSelected: "Selected text",
|
|
17
|
+
toolbar: "Template fields",
|
|
18
|
+
fieldChip: (label) => `Field: ${label}`,
|
|
19
|
+
};
|
|
20
|
+
const resolveEditorLabels = (labels) => ({
|
|
21
|
+
...exports.DEFAULT_EDITOR_LABELS,
|
|
22
|
+
...labels,
|
|
23
|
+
});
|
|
24
|
+
exports.resolveEditorLabels = resolveEditorLabels;
|
|
@@ -0,0 +1,28 @@
|
|
|
1
|
+
import type { PaletteProps } from "../../Theme/tokens/types";
|
|
2
|
+
export declare const chipColors: (colors: PaletteProps) => {
|
|
3
|
+
known: {
|
|
4
|
+
bg: string;
|
|
5
|
+
ink: string;
|
|
6
|
+
};
|
|
7
|
+
unknown: {
|
|
8
|
+
bg: string;
|
|
9
|
+
ink: string;
|
|
10
|
+
};
|
|
11
|
+
};
|
|
12
|
+
export declare const chipStyles: (colors: PaletteProps) => {
|
|
13
|
+
".pxl-token": {
|
|
14
|
+
display: string;
|
|
15
|
+
px: string;
|
|
16
|
+
borderRadius: string;
|
|
17
|
+
border: string;
|
|
18
|
+
bg: string;
|
|
19
|
+
color: string;
|
|
20
|
+
cursor: string;
|
|
21
|
+
};
|
|
22
|
+
".pxl-token[data-known=\"false\"]": {
|
|
23
|
+
bg: string;
|
|
24
|
+
color: string;
|
|
25
|
+
border: string;
|
|
26
|
+
borderColor: string;
|
|
27
|
+
};
|
|
28
|
+
};
|
|
@@ -0,0 +1,30 @@
|
|
|
1
|
+
"use strict";
|
|
2
|
+
Object.defineProperty(exports, "__esModule", { value: true });
|
|
3
|
+
exports.chipStyles = exports.chipColors = void 0;
|
|
4
|
+
const editorTokens_1 = require("./editorTokens");
|
|
5
|
+
const chipColors = (colors) => ({
|
|
6
|
+
known: { bg: colors.primary.opacity[8], ink: colors.accentText },
|
|
7
|
+
unknown: { bg: "transparent", ink: colors.semanticText.error },
|
|
8
|
+
});
|
|
9
|
+
exports.chipColors = chipColors;
|
|
10
|
+
const chipStyles = (colors) => {
|
|
11
|
+
const { known, unknown } = (0, exports.chipColors)(colors);
|
|
12
|
+
return {
|
|
13
|
+
[`.${editorTokens_1.CHIP_CLASS}`]: {
|
|
14
|
+
display: "inline-block",
|
|
15
|
+
px: "0.25rem",
|
|
16
|
+
borderRadius: "sm",
|
|
17
|
+
border: "1px solid transparent",
|
|
18
|
+
bg: known.bg,
|
|
19
|
+
color: known.ink,
|
|
20
|
+
cursor: "default",
|
|
21
|
+
},
|
|
22
|
+
[`.${editorTokens_1.CHIP_CLASS}[data-known="false"]`]: {
|
|
23
|
+
bg: unknown.bg,
|
|
24
|
+
color: unknown.ink,
|
|
25
|
+
border: "1px dashed",
|
|
26
|
+
borderColor: unknown.ink,
|
|
27
|
+
},
|
|
28
|
+
};
|
|
29
|
+
};
|
|
30
|
+
exports.chipStyles = chipStyles;
|
|
@@ -0,0 +1,26 @@
|
|
|
1
|
+
import type { EditorMergeField, EditorTokenSyntax } from "./EditorProps";
|
|
2
|
+
import type { OptionProp } from "../Select/SelectProps";
|
|
3
|
+
export declare const DEFAULT_TOKEN_SYNTAX: EditorTokenSyntax;
|
|
4
|
+
export declare const CHIP_CLASS = "pxl-token";
|
|
5
|
+
export declare const fieldToken: (path: string, syntax?: EditorTokenSyntax) => string;
|
|
6
|
+
export declare function fieldOptions(fields: EditorMergeField[], syntax?: EditorTokenSyntax): OptionProp[];
|
|
7
|
+
export declare function extractTokens(html: string, syntax?: EditorTokenSyntax): string[];
|
|
8
|
+
export declare function unknownTokens(html: string, fields: EditorMergeField[], syntax?: EditorTokenSyntax): string[];
|
|
9
|
+
/** Replaces every whitespace-insensitive occurrence of `selectedText` outside tags and tokens. */
|
|
10
|
+
export declare function makeDynamic(html: string, selectedText: string, path: string, syntax?: EditorTokenSyntax): {
|
|
11
|
+
html: string;
|
|
12
|
+
count: number;
|
|
13
|
+
};
|
|
14
|
+
export declare function countOccurrences(html: string, selectedText: string, syntax?: EditorTokenSyntax): number;
|
|
15
|
+
export type ChipContext = {
|
|
16
|
+
fields: EditorMergeField[];
|
|
17
|
+
syntax: EditorTokenSyntax;
|
|
18
|
+
chipLabel: (label: string) => string;
|
|
19
|
+
};
|
|
20
|
+
export declare function chipHtml(path: string, { fields, syntax, chipLabel }: ChipContext): string;
|
|
21
|
+
/** Raw `${path}` tokens in text nodes become non-editable chip spans; tags are left alone. */
|
|
22
|
+
export declare function chipify(html: string, context: ChipContext): string;
|
|
23
|
+
/** Inverse of `chipify`: every chip span collapses back to its raw token. */
|
|
24
|
+
export declare function serializeChips(html: string, syntax?: EditorTokenSyntax): string;
|
|
25
|
+
/** The chip a Backspace (backward) or Delete (forward) at a collapsed caret would eat, if any. */
|
|
26
|
+
export declare function adjacentChip(range: Range, direction: "backward" | "forward"): HTMLElement | null;
|
|
@@ -0,0 +1,134 @@
|
|
|
1
|
+
"use strict";
|
|
2
|
+
Object.defineProperty(exports, "__esModule", { value: true });
|
|
3
|
+
exports.fieldToken = exports.CHIP_CLASS = exports.DEFAULT_TOKEN_SYNTAX = void 0;
|
|
4
|
+
exports.fieldOptions = fieldOptions;
|
|
5
|
+
exports.extractTokens = extractTokens;
|
|
6
|
+
exports.unknownTokens = unknownTokens;
|
|
7
|
+
exports.makeDynamic = makeDynamic;
|
|
8
|
+
exports.countOccurrences = countOccurrences;
|
|
9
|
+
exports.chipHtml = chipHtml;
|
|
10
|
+
exports.chipify = chipify;
|
|
11
|
+
exports.serializeChips = serializeChips;
|
|
12
|
+
exports.adjacentChip = adjacentChip;
|
|
13
|
+
exports.DEFAULT_TOKEN_SYNTAX = { open: "${", close: "}" };
|
|
14
|
+
exports.CHIP_CLASS = "pxl-token";
|
|
15
|
+
const PATH_CHARS = "[A-Za-z0-9_.]+";
|
|
16
|
+
const TAG_SPLIT = /(<[^>]*>)/;
|
|
17
|
+
const CHIP_PATTERN = /<span\b([^>]*\bdata-field=(["'])([^"']*)\2[^>]*)>[^<]*<\/span>/g;
|
|
18
|
+
const escapeRegExp = (text) => text.replace(/[.*+?^${}()|[\]\\]/g, "\\$&");
|
|
19
|
+
const escapeHtml = (text) => text.replace(/&/g, "&").replace(/</g, "<").replace(/>/g, ">");
|
|
20
|
+
const escapeAttr = (text) => escapeHtml(text).replace(/"/g, """);
|
|
21
|
+
const patternsFor = ({ open, close }) => {
|
|
22
|
+
const o = escapeRegExp(open);
|
|
23
|
+
const c = escapeRegExp(close);
|
|
24
|
+
return {
|
|
25
|
+
match: new RegExp(`${o}(${PATH_CHARS})${c}`, "g"),
|
|
26
|
+
split: new RegExp(`(${o}(?:(?!${c})[\\s\\S])*${c})`),
|
|
27
|
+
};
|
|
28
|
+
};
|
|
29
|
+
const fieldToken = (path, syntax = exports.DEFAULT_TOKEN_SYNTAX) => `${syntax.open}${path}${syntax.close}`;
|
|
30
|
+
exports.fieldToken = fieldToken;
|
|
31
|
+
function fieldOptions(fields, syntax = exports.DEFAULT_TOKEN_SYNTAX) {
|
|
32
|
+
const groups = [...new Set(fields.map((field) => field.group))];
|
|
33
|
+
return groups.flatMap((group) => fields
|
|
34
|
+
.filter((field) => field.group === group)
|
|
35
|
+
.map((field) => ({
|
|
36
|
+
id: field.path,
|
|
37
|
+
label: field.label,
|
|
38
|
+
group,
|
|
39
|
+
description: (0, exports.fieldToken)(field.path, syntax),
|
|
40
|
+
})));
|
|
41
|
+
}
|
|
42
|
+
function extractTokens(html, syntax = exports.DEFAULT_TOKEN_SYNTAX) {
|
|
43
|
+
const { match } = patternsFor(syntax);
|
|
44
|
+
return [...new Set([...html.matchAll(match)].map((m) => m[1]))];
|
|
45
|
+
}
|
|
46
|
+
function unknownTokens(html, fields, syntax = exports.DEFAULT_TOKEN_SYNTAX) {
|
|
47
|
+
const known = new Set(fields.map((field) => field.path));
|
|
48
|
+
return extractTokens(html, syntax).filter((path) => !known.has(path));
|
|
49
|
+
}
|
|
50
|
+
function needlePattern(text) {
|
|
51
|
+
const words = text
|
|
52
|
+
.trim()
|
|
53
|
+
.split(/\s+/)
|
|
54
|
+
.map((word) => escapeRegExp(escapeHtml(word)));
|
|
55
|
+
return new RegExp(words.join("(?:\\s| |\\u00a0)+"), "g");
|
|
56
|
+
}
|
|
57
|
+
function mapTextOutsideTokens(html, syntax, mapText) {
|
|
58
|
+
const { split } = patternsFor(syntax);
|
|
59
|
+
return html
|
|
60
|
+
.split(TAG_SPLIT)
|
|
61
|
+
.map((segment) => segment.startsWith("<")
|
|
62
|
+
? segment
|
|
63
|
+
: segment
|
|
64
|
+
.split(split)
|
|
65
|
+
.map((part, i) => (i % 2 === 1 ? part : mapText(part)))
|
|
66
|
+
.join(""))
|
|
67
|
+
.join("");
|
|
68
|
+
}
|
|
69
|
+
/** Replaces every whitespace-insensitive occurrence of `selectedText` outside tags and tokens. */
|
|
70
|
+
function makeDynamic(html, selectedText, path, syntax = exports.DEFAULT_TOKEN_SYNTAX) {
|
|
71
|
+
if (!selectedText.trim())
|
|
72
|
+
return { html, count: 0 };
|
|
73
|
+
const pattern = needlePattern(selectedText);
|
|
74
|
+
let count = 0;
|
|
75
|
+
const next = mapTextOutsideTokens(html, syntax, (text) => text.replace(pattern, () => {
|
|
76
|
+
count += 1;
|
|
77
|
+
return (0, exports.fieldToken)(path, syntax);
|
|
78
|
+
}));
|
|
79
|
+
return { html: next, count };
|
|
80
|
+
}
|
|
81
|
+
function countOccurrences(html, selectedText, syntax = exports.DEFAULT_TOKEN_SYNTAX) {
|
|
82
|
+
return makeDynamic(html, selectedText, "_", syntax).count;
|
|
83
|
+
}
|
|
84
|
+
function chipHtml(path, { fields, syntax, chipLabel }) {
|
|
85
|
+
const field = fields.find((f) => f.path === path);
|
|
86
|
+
const text = field ? field.label : (0, exports.fieldToken)(path, syntax);
|
|
87
|
+
const title = (field === null || field === void 0 ? void 0 : field.sample) ? ` title="${escapeAttr(field.sample)}"` : "";
|
|
88
|
+
return (`<span class="${exports.CHIP_CLASS}" data-field="${escapeAttr(path)}" data-known="${field ? "true" : "false"}"` +
|
|
89
|
+
` contenteditable="false" role="img" aria-label="${escapeAttr(chipLabel(text))}"${title}>${escapeHtml(text)}</span>`);
|
|
90
|
+
}
|
|
91
|
+
/** Raw `${path}` tokens in text nodes become non-editable chip spans; tags are left alone. */
|
|
92
|
+
function chipify(html, context) {
|
|
93
|
+
const { match } = patternsFor(context.syntax);
|
|
94
|
+
return html
|
|
95
|
+
.split(TAG_SPLIT)
|
|
96
|
+
.map((segment) => segment.startsWith("<") ? segment : segment.replace(match, (_t, path) => chipHtml(path, context)))
|
|
97
|
+
.join("");
|
|
98
|
+
}
|
|
99
|
+
/** Inverse of `chipify`: every chip span collapses back to its raw token. */
|
|
100
|
+
function serializeChips(html, syntax = exports.DEFAULT_TOKEN_SYNTAX) {
|
|
101
|
+
return html.replace(CHIP_PATTERN, (_m, _attrs, _q, path) => (0, exports.fieldToken)(path, syntax));
|
|
102
|
+
}
|
|
103
|
+
const isChip = (node) => !!node && node.nodeType === 1 && node.hasAttribute("data-field");
|
|
104
|
+
const INVISIBLE = /[\u200b\ufeff]/g;
|
|
105
|
+
const isBlankText = (node) => !node.data.replace(INVISIBLE, "");
|
|
106
|
+
const skipEmptyText = (node, step) => {
|
|
107
|
+
let current = node;
|
|
108
|
+
while (current && current.nodeType === 3 && isBlankText(current))
|
|
109
|
+
current = current[step];
|
|
110
|
+
return current;
|
|
111
|
+
};
|
|
112
|
+
/** The chip a Backspace (backward) or Delete (forward) at a collapsed caret would eat, if any. */
|
|
113
|
+
function adjacentChip(range, direction) {
|
|
114
|
+
var _a;
|
|
115
|
+
if (!range.collapsed)
|
|
116
|
+
return null;
|
|
117
|
+
const node = range.startContainer;
|
|
118
|
+
const offset = range.startOffset;
|
|
119
|
+
const step = direction === "backward" ? "previousSibling" : "nextSibling";
|
|
120
|
+
let candidate;
|
|
121
|
+
if (node.nodeType === 3) {
|
|
122
|
+
const text = node.data;
|
|
123
|
+
const beyond = direction === "backward" ? text.slice(0, offset) : text.slice(offset);
|
|
124
|
+
const atEdge = !beyond.replace(INVISIBLE, "");
|
|
125
|
+
if (!atEdge)
|
|
126
|
+
return null;
|
|
127
|
+
candidate = node[step];
|
|
128
|
+
}
|
|
129
|
+
else {
|
|
130
|
+
candidate = (_a = node.childNodes[direction === "backward" ? offset - 1 : offset]) !== null && _a !== void 0 ? _a : null;
|
|
131
|
+
}
|
|
132
|
+
const found = skipEmptyText(candidate, step);
|
|
133
|
+
return isChip(found) ? found : null;
|
|
134
|
+
}
|
|
@@ -0,0 +1,40 @@
|
|
|
1
|
+
import type { Ref } from "react";
|
|
2
|
+
import type { EditorApi, EditorMergeField, EditorTokenSyntax } from "./EditorProps";
|
|
3
|
+
import { type ChipContext } from "./editorTokens";
|
|
4
|
+
export type JoditLike = {
|
|
5
|
+
value: string;
|
|
6
|
+
editor: HTMLElement;
|
|
7
|
+
s: {
|
|
8
|
+
isInsideArea: boolean;
|
|
9
|
+
range: Range;
|
|
10
|
+
selectRange: (range: Range, focus?: boolean) => unknown;
|
|
11
|
+
insertHTML: (html: string) => void;
|
|
12
|
+
focus: () => unknown;
|
|
13
|
+
};
|
|
14
|
+
events: {
|
|
15
|
+
on: (events: string, handler: (event: never) => unknown) => unknown;
|
|
16
|
+
};
|
|
17
|
+
synchronizeValues: () => void;
|
|
18
|
+
waitForReady: () => Promise<unknown>;
|
|
19
|
+
};
|
|
20
|
+
type BridgeArgs = {
|
|
21
|
+
value?: string;
|
|
22
|
+
onChange?: (value: string) => void;
|
|
23
|
+
onBlur?: (value: string, event: never) => void;
|
|
24
|
+
mergeFields?: EditorMergeField[];
|
|
25
|
+
syntax: EditorTokenSyntax;
|
|
26
|
+
chipLabel: (label: string) => string;
|
|
27
|
+
apiRef?: Ref<EditorApi>;
|
|
28
|
+
onReady?: () => void;
|
|
29
|
+
onUnknownTokens?: (paths: string[]) => void;
|
|
30
|
+
};
|
|
31
|
+
export declare function useEditorBridge({ value, onChange, onBlur, mergeFields, syntax, chipLabel, apiRef, onReady, onUnknownTokens, }: BridgeArgs): {
|
|
32
|
+
joditValue: string | undefined;
|
|
33
|
+
attachEditor: (jodit: JoditLike) => void;
|
|
34
|
+
api: EditorApi;
|
|
35
|
+
instance: JoditLike | null;
|
|
36
|
+
raw: string;
|
|
37
|
+
unknown: string[];
|
|
38
|
+
ctx: ChipContext;
|
|
39
|
+
};
|
|
40
|
+
export {};
|