@smwb/ui-react 2.8.0 → 2.10.0
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- package/AI_LESS_OVERRIDES.md +84 -21
- package/AI_THEMING.md +72 -28
- package/README.md +654 -0
- package/dist/assets/styles/less/components/appBar/appBar.entry.css +1 -1
- package/dist/assets/styles/less/components/badge/badge.entry.css +1 -1
- package/dist/assets/styles/less/components/button/button.entry.css +1 -1
- package/dist/assets/styles/less/components/checkbox/checkbox.entry.css +1 -1
- package/dist/assets/styles/less/components/chip/chip.entry.css +1 -1
- package/dist/assets/styles/less/components/commandPalette/commandPalette.entry.css +1 -0
- package/dist/assets/styles/less/components/composer/composer.entry.css +1 -0
- package/dist/assets/styles/less/components/dagView/dagView.entry.css +1 -0
- package/dist/assets/styles/less/components/diffStat/diffStat.entry.css +1 -0
- package/dist/assets/styles/less/components/kbd/kbd.entry.css +1 -0
- package/dist/assets/styles/less/components/list/list.entry.css +1 -1
- package/dist/assets/styles/less/components/qrCode/qrCode.entry.css +1 -0
- package/dist/assets/styles/less/components/radioButton/radioButton.entry.css +1 -1
- package/dist/assets/styles/less/components/selectField/selectField.entry.css +1 -1
- package/dist/assets/styles/less/components/sidebar/sidebar.entry.css +1 -1
- package/dist/assets/styles/less/components/statusDot/statusDot.entry.css +1 -0
- package/dist/assets/styles/less/components/swimlanes/swimlanes.entry.css +1 -0
- package/dist/assets/styles/less/components/tabGroups/tabGroups.entry.css +1 -0
- package/dist/assets/styles/less/components/tabs/tab/tab.entry.css +1 -1
- package/dist/assets/styles/less/components/tabs/tabPanel/tabPanel.entry.css +1 -0
- package/dist/assets/styles/less/components/tabs/tabs.entry.css +1 -1
- package/dist/assets/styles/less/components/textField/textField.entry.css +1 -1
- package/dist/assets/styles/less/components/toggle/toggle.entry.css +1 -1
- package/dist/assets/styles/less/components/treeView/treeView.entry.css +1 -1
- package/dist/assets/styles/less/tokens.entry.css +1 -1
- package/dist/components/dataDisplay/badge/badge.d.ts +2 -1
- package/dist/components/dataDisplay/badge/badge.js.map +1 -1
- package/dist/components/dataDisplay/chat/chat.d.ts +43 -1
- package/dist/components/dataDisplay/chat/chat.js +179 -150
- package/dist/components/dataDisplay/chat/chat.js.map +1 -1
- package/dist/components/dataDisplay/chat/chatComposer.d.ts +17 -0
- package/dist/components/dataDisplay/chat/chatComposer.js +31 -29
- package/dist/components/dataDisplay/chat/chatComposer.js.map +1 -1
- package/dist/components/dataDisplay/chat/index.d.ts +1 -1
- package/dist/components/dataDisplay/chat/utils.d.ts +14 -0
- package/dist/components/dataDisplay/chat/utils.js.map +1 -1
- package/dist/components/dataDisplay/dagView/dagLayout.d.ts +74 -0
- package/dist/components/dataDisplay/dagView/dagLayout.js +289 -0
- package/dist/components/dataDisplay/dagView/dagLayout.js.map +1 -0
- package/dist/components/dataDisplay/dagView/dagView.d.ts +157 -0
- package/dist/components/dataDisplay/dagView/dagView.js +543 -0
- package/dist/components/dataDisplay/dagView/dagView.js.map +1 -0
- package/dist/components/dataDisplay/dagView/index.d.ts +4 -0
- package/dist/components/dataDisplay/dagView/panZoom.d.ts +75 -0
- package/dist/components/dataDisplay/dagView/panZoom.js +171 -0
- package/dist/components/dataDisplay/dagView/panZoom.js.map +1 -0
- package/dist/components/dataDisplay/diffStat/diffStat.d.ts +54 -0
- package/dist/components/dataDisplay/diffStat/diffStat.js +63 -0
- package/dist/components/dataDisplay/diffStat/diffStat.js.map +1 -0
- package/dist/components/dataDisplay/diffStat/index.d.ts +2 -0
- package/dist/components/dataDisplay/kbd/index.d.ts +4 -0
- package/dist/components/dataDisplay/kbd/kbd.d.ts +40 -0
- package/dist/components/dataDisplay/kbd/kbd.js +27 -0
- package/dist/components/dataDisplay/kbd/kbd.js.map +1 -0
- package/dist/components/dataDisplay/kbd/kbdKeys.d.ts +18 -0
- package/dist/components/dataDisplay/kbd/kbdKeys.js +72 -0
- package/dist/components/dataDisplay/kbd/kbdKeys.js.map +1 -0
- package/dist/components/dataDisplay/list/listItem.d.ts +34 -0
- package/dist/components/dataDisplay/list/listItem.js +47 -24
- package/dist/components/dataDisplay/list/listItem.js.map +1 -1
- package/dist/components/dataDisplay/qrCode/index.d.ts +2 -0
- package/dist/components/dataDisplay/qrCode/qrCode.d.ts +28 -0
- package/dist/components/dataDisplay/qrCode/qrCode.js +78 -0
- package/dist/components/dataDisplay/qrCode/qrCode.js.map +1 -0
- package/dist/components/dataDisplay/qrCode/qrCodePath.d.ts +7 -0
- package/dist/components/dataDisplay/qrCode/qrCodePath.js +20 -0
- package/dist/components/dataDisplay/qrCode/qrCodePath.js.map +1 -0
- package/dist/components/dataDisplay/statusDot/index.d.ts +2 -0
- package/dist/components/dataDisplay/statusDot/statusDot.d.ts +35 -0
- package/dist/components/dataDisplay/statusDot/statusDot.js +30 -0
- package/dist/components/dataDisplay/statusDot/statusDot.js.map +1 -0
- package/dist/components/dataDisplay/swimlanes/index.d.ts +2 -0
- package/dist/components/dataDisplay/swimlanes/swimlanes.d.ts +53 -0
- package/dist/components/dataDisplay/swimlanes/swimlanes.js +357 -0
- package/dist/components/dataDisplay/swimlanes/swimlanes.js.map +1 -0
- package/dist/components/dataDisplay/treeView/treeView.d.ts +17 -1
- package/dist/components/dataDisplay/treeView/treeView.js +113 -92
- package/dist/components/dataDisplay/treeView/treeView.js.map +1 -1
- package/dist/components/feedBack/modal/modal.js +84 -63
- package/dist/components/feedBack/modal/modal.js.map +1 -1
- package/dist/components/inputs/button/button.d.ts +13 -1
- package/dist/components/inputs/button/button.js +57 -51
- package/dist/components/inputs/button/button.js.map +1 -1
- package/dist/components/inputs/composer/composer.d.ts +149 -0
- package/dist/components/inputs/composer/composer.js +219 -0
- package/dist/components/inputs/composer/composer.js.map +1 -0
- package/dist/components/inputs/composer/composerFiles.d.ts +26 -0
- package/dist/components/inputs/composer/composerFiles.js +19 -0
- package/dist/components/inputs/composer/composerFiles.js.map +1 -0
- package/dist/components/inputs/composer/composerKeys.d.ts +29 -0
- package/dist/components/inputs/composer/composerKeys.js +7 -0
- package/dist/components/inputs/composer/composerKeys.js.map +1 -0
- package/dist/components/inputs/composer/index.d.ts +3 -0
- package/dist/components/layout/sheet/sheet.d.ts +12 -0
- package/dist/components/layout/sheet/sheet.js +152 -137
- package/dist/components/layout/sheet/sheet.js.map +1 -1
- package/dist/components/layout/tabGroups/index.d.ts +4 -0
- package/dist/components/layout/tabGroups/tabGroups.d.ts +94 -0
- package/dist/components/layout/tabGroups/tabGroups.js +783 -0
- package/dist/components/layout/tabGroups/tabGroups.js.map +1 -0
- package/dist/components/layout/tabGroups/tabGroupsFocus.d.ts +55 -0
- package/dist/components/layout/tabGroups/tabGroupsFocus.js +199 -0
- package/dist/components/layout/tabGroups/tabGroupsFocus.js.map +1 -0
- package/dist/components/layout/tabGroups/tabGroupsLayout.d.ts +250 -0
- package/dist/components/layout/tabGroups/tabGroupsLayout.js +497 -0
- package/dist/components/layout/tabGroups/tabGroupsLayout.js.map +1 -0
- package/dist/components/navigation/appBar/appBar.d.ts +22 -0
- package/dist/components/navigation/appBar/appBar.js +31 -26
- package/dist/components/navigation/appBar/appBar.js.map +1 -1
- package/dist/components/navigation/commandPalette/commandPalette.d.ts +111 -0
- package/dist/components/navigation/commandPalette/commandPalette.js +337 -0
- package/dist/components/navigation/commandPalette/commandPalette.js.map +1 -0
- package/dist/components/navigation/commandPalette/commandPaletteFilter.d.ts +11 -0
- package/dist/components/navigation/commandPalette/commandPaletteFilter.js +16 -0
- package/dist/components/navigation/commandPalette/commandPaletteFilter.js.map +1 -0
- package/dist/components/navigation/commandPalette/commandPaletteNavigation.d.ts +13 -0
- package/dist/components/navigation/commandPalette/commandPaletteNavigation.js +38 -0
- package/dist/components/navigation/commandPalette/commandPaletteNavigation.js.map +1 -0
- package/dist/components/navigation/commandPalette/commandPaletteTypes.d.ts +39 -0
- package/dist/components/navigation/commandPalette/index.d.ts +4 -0
- package/dist/components/navigation/sidebar/sidebar.d.ts +10 -0
- package/dist/components/navigation/sidebar/sidebar.js +61 -59
- package/dist/components/navigation/sidebar/sidebar.js.map +1 -1
- package/dist/components/navigation/tabs/index.d.ts +3 -1
- package/dist/components/navigation/tabs/tab/tab.d.ts +88 -1
- package/dist/components/navigation/tabs/tab/tab.js +121 -42
- package/dist/components/navigation/tabs/tab/tab.js.map +1 -1
- package/dist/components/navigation/tabs/tabPanel/tabPanel.d.ts +19 -0
- package/dist/components/navigation/tabs/tabPanel/tabPanel.js +27 -0
- package/dist/components/navigation/tabs/tabPanel/tabPanel.js.map +1 -0
- package/dist/components/navigation/tabs/tabs.d.ts +79 -6
- package/dist/components/navigation/tabs/tabs.js +369 -145
- package/dist/components/navigation/tabs/tabs.js.map +1 -1
- package/dist/components/navigation/tabs/tabs.utils.d.ts +20 -0
- package/dist/components/navigation/tabs/tabs.utils.js +11 -0
- package/dist/components/navigation/tabs/tabs.utils.js.map +1 -0
- package/dist/components/navigation/tabs/tabsContext.d.ts +11 -0
- package/dist/components/navigation/tabs/tabsContext.js +6 -0
- package/dist/components/navigation/tabs/tabsContext.js.map +1 -0
- package/dist/headless/components/dataDisplay/badge/badge.js.map +1 -1
- package/dist/headless/components/dataDisplay/chat/chat.js +179 -150
- package/dist/headless/components/dataDisplay/chat/chat.js.map +1 -1
- package/dist/headless/components/dataDisplay/chat/chatComposer.js +31 -29
- package/dist/headless/components/dataDisplay/chat/chatComposer.js.map +1 -1
- package/dist/headless/components/dataDisplay/chat/utils.js.map +1 -1
- package/dist/headless/components/dataDisplay/dagView/dagLayout.js +289 -0
- package/dist/headless/components/dataDisplay/dagView/dagLayout.js.map +1 -0
- package/dist/headless/components/dataDisplay/dagView/dagView.js +541 -0
- package/dist/headless/components/dataDisplay/dagView/dagView.js.map +1 -0
- package/dist/headless/components/dataDisplay/dagView/panZoom.js +171 -0
- package/dist/headless/components/dataDisplay/dagView/panZoom.js.map +1 -0
- package/dist/headless/components/dataDisplay/diffStat/diffStat.js +61 -0
- package/dist/headless/components/dataDisplay/diffStat/diffStat.js.map +1 -0
- package/dist/headless/components/dataDisplay/kbd/kbd.js +25 -0
- package/dist/headless/components/dataDisplay/kbd/kbd.js.map +1 -0
- package/dist/headless/components/dataDisplay/kbd/kbdKeys.js +72 -0
- package/dist/headless/components/dataDisplay/kbd/kbdKeys.js.map +1 -0
- package/dist/headless/components/dataDisplay/list/listItem.js +47 -24
- package/dist/headless/components/dataDisplay/list/listItem.js.map +1 -1
- package/dist/headless/components/dataDisplay/qrCode/qrCode.js +76 -0
- package/dist/headless/components/dataDisplay/qrCode/qrCode.js.map +1 -0
- package/dist/headless/components/dataDisplay/qrCode/qrCodePath.js +20 -0
- package/dist/headless/components/dataDisplay/qrCode/qrCodePath.js.map +1 -0
- package/dist/headless/components/dataDisplay/statusDot/statusDot.js +28 -0
- package/dist/headless/components/dataDisplay/statusDot/statusDot.js.map +1 -0
- package/dist/headless/components/dataDisplay/swimlanes/swimlanes.js +355 -0
- package/dist/headless/components/dataDisplay/swimlanes/swimlanes.js.map +1 -0
- package/dist/headless/components/dataDisplay/treeView/treeView.js +113 -92
- package/dist/headless/components/dataDisplay/treeView/treeView.js.map +1 -1
- package/dist/headless/components/feedBack/modal/modal.js +85 -64
- package/dist/headless/components/feedBack/modal/modal.js.map +1 -1
- package/dist/headless/components/inputs/button/button.js +56 -50
- package/dist/headless/components/inputs/button/button.js.map +1 -1
- package/dist/headless/components/inputs/composer/composer.js +217 -0
- package/dist/headless/components/inputs/composer/composer.js.map +1 -0
- package/dist/headless/components/inputs/composer/composerFiles.js +19 -0
- package/dist/headless/components/inputs/composer/composerFiles.js.map +1 -0
- package/dist/headless/components/inputs/composer/composerKeys.js +7 -0
- package/dist/headless/components/inputs/composer/composerKeys.js.map +1 -0
- package/dist/headless/components/layout/sheet/sheet.js +160 -145
- package/dist/headless/components/layout/sheet/sheet.js.map +1 -1
- package/dist/headless/components/layout/tabGroups/tabGroups.js +781 -0
- package/dist/headless/components/layout/tabGroups/tabGroups.js.map +1 -0
- package/dist/headless/components/layout/tabGroups/tabGroupsFocus.js +199 -0
- package/dist/headless/components/layout/tabGroups/tabGroupsFocus.js.map +1 -0
- package/dist/headless/components/layout/tabGroups/tabGroupsLayout.js +497 -0
- package/dist/headless/components/layout/tabGroups/tabGroupsLayout.js.map +1 -0
- package/dist/headless/components/navigation/appBar/appBar.js +35 -30
- package/dist/headless/components/navigation/appBar/appBar.js.map +1 -1
- package/dist/headless/components/navigation/commandPalette/commandPalette.js +335 -0
- package/dist/headless/components/navigation/commandPalette/commandPalette.js.map +1 -0
- package/dist/headless/components/navigation/commandPalette/commandPaletteFilter.js +16 -0
- package/dist/headless/components/navigation/commandPalette/commandPaletteFilter.js.map +1 -0
- package/dist/headless/components/navigation/commandPalette/commandPaletteNavigation.js +38 -0
- package/dist/headless/components/navigation/commandPalette/commandPaletteNavigation.js.map +1 -0
- package/dist/headless/components/navigation/sidebar/sidebar.js +56 -54
- package/dist/headless/components/navigation/sidebar/sidebar.js.map +1 -1
- package/dist/headless/components/navigation/tabs/tab/tab.js +121 -42
- package/dist/headless/components/navigation/tabs/tab/tab.js.map +1 -1
- package/dist/headless/components/navigation/tabs/tabPanel/tabPanel.js +25 -0
- package/dist/headless/components/navigation/tabs/tabPanel/tabPanel.js.map +1 -0
- package/dist/headless/components/navigation/tabs/tabs.js +369 -145
- package/dist/headless/components/navigation/tabs/tabs.js.map +1 -1
- package/dist/headless/components/navigation/tabs/tabs.utils.js +11 -0
- package/dist/headless/components/navigation/tabs/tabs.utils.js.map +1 -0
- package/dist/headless/components/navigation/tabs/tabsContext.js +6 -0
- package/dist/headless/components/navigation/tabs/tabsContext.js.map +1 -0
- package/dist/headless/hooks/useFocusTrap.js +24 -21
- package/dist/headless/hooks/useFocusTrap.js.map +1 -1
- package/dist/headless/hooks/useKeyboardShortcut.js +19 -0
- package/dist/headless/hooks/useKeyboardShortcut.js.map +1 -0
- package/dist/headless/index.js +360 -316
- package/dist/headless/index.js.map +1 -1
- package/dist/headless/utils/keyboardShortcut.js +49 -0
- package/dist/headless/utils/keyboardShortcut.js.map +1 -0
- package/dist/headless/utils/linkAttrs.js +13 -0
- package/dist/headless/utils/linkAttrs.js.map +1 -0
- package/dist/headless/utils/restoreFocus.js +10 -0
- package/dist/headless/utils/restoreFocus.js.map +1 -0
- package/dist/hooks/useFocusTrap.d.ts +6 -1
- package/dist/hooks/useFocusTrap.js +24 -21
- package/dist/hooks/useFocusTrap.js.map +1 -1
- package/dist/hooks/useKeyboardShortcut.d.ts +30 -0
- package/dist/hooks/useKeyboardShortcut.js +19 -0
- package/dist/hooks/useKeyboardShortcut.js.map +1 -0
- package/dist/index.cjs +3 -2
- package/dist/index.cjs.map +1 -1
- package/dist/index.d.ts +24 -3
- package/dist/index.js +360 -316
- package/dist/index.js.map +1 -1
- package/dist/utils/keyboardShortcut.d.ts +12 -0
- package/dist/utils/keyboardShortcut.js +49 -0
- package/dist/utils/keyboardShortcut.js.map +1 -0
- package/dist/utils/linkAttrs.d.ts +13 -0
- package/dist/utils/linkAttrs.js +13 -0
- package/dist/utils/linkAttrs.js.map +1 -0
- package/dist/utils/restoreFocus.d.ts +8 -0
- package/dist/utils/restoreFocus.js +10 -0
- package/dist/utils/restoreFocus.js.map +1 -0
- package/package.json +5 -3
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"chatComposer.js","sources":["../../../../src/components/dataDisplay/chat/chatComposer.tsx"],"sourcesContent":["import React, { useId, useRef, useState } from \"react\";\nimport cn from \"clsx\";\nimport Icon from \"../../base/icon/icon\";\nimport { TextField } from \"../../inputs/textField\";\nimport { TextFieldWrapper } from \"../../inputs/textField/textFieldWrapper\";\nimport ChatIconButton from \"./chatIconButton\";\nimport { shouldComposerNewlineOnEnter } from \"./utils\";\n\nexport interface ChatComposerProps {\n className?: string;\n onSendMessage?: (text: string) => void | Promise<void>;\n placeholder?: string;\n disabled?: boolean;\n sendAriaLabel?: string;\n shiftEnterNewline?: boolean;\n ctrlEnterNewline?: boolean;\n fileUpload?: boolean;\n attachInputId?: string;\n onAttachClick?: () => void;\n attachAriaLabel?: string;\n}\n\nfunction stopPropagation(event: React.SyntheticEvent) {\n event.stopPropagation();\n}\n\nfunction insertNewlineAtCursor(element: HTMLTextAreaElement, value: string, setValue: (next: string) => void) {\n const start = element.selectionStart ?? value.length;\n const end = element.selectionEnd ?? value.length;\n const nextValue = `${value.slice(0, start)}\\n${value.slice(end)}`;\n\n setValue(nextValue);\n\n requestAnimationFrame(() => {\n element.selectionStart = start + 1;\n element.selectionEnd = start + 1;\n });\n}\n\nexport function ChatComposer({\n className,\n onSendMessage,\n placeholder = \"message\",\n disabled = false,\n sendAriaLabel = \"Send message\",\n shiftEnterNewline = true,\n ctrlEnterNewline = true,\n fileUpload = false,\n attachInputId,\n onAttachClick,\n attachAriaLabel = \"Attach file\",\n}: ChatComposerProps) {\n const [value, setValue] = useState(\"\");\n const [isFocused, setIsFocused] = useState(false);\n const inputId = useId();\n const textareaRef = useRef<HTMLTextAreaElement>(null);\n const multiline = shiftEnterNewline || ctrlEnterNewline;\n const canSend = Boolean(onSendMessage) && value.trim().length > 0 && !disabled;\n const showAttach = fileUpload && Boolean(attachInputId || onAttachClick);\n\n const handleSend = () => {\n if (!onSendMessage) {\n return;\n }\n\n const text = value.trim();\n\n if (!text || disabled) {\n return;\n }\n\n void onSendMessage(text);\n setValue(\"\");\n };\n\n const handleKeyDown = (event: React.KeyboardEvent<HTMLInputElement | HTMLTextAreaElement>) => {\n if (shouldComposerNewlineOnEnter(event, { shiftEnterNewline, ctrlEnterNewline })) {\n if (event.currentTarget instanceof HTMLTextAreaElement) {\n event.preventDefault();\n insertNewlineAtCursor(event.currentTarget, value, setValue);\n }\n\n return;\n }\n\n if (event.key !== \"Enter\") {\n return;\n }\n\n event.preventDefault();\n handleSend();\n };\n\n const attachClassName = cn(\n \"smwb-chat-icon-button\",\n \"smwb-chat-icon-button_edge-start\",\n disabled && \"smwb-chat-icon-button_disabled\"\n );\n\n const attachButton = showAttach ? (\n attachInputId ? (\n <label\n htmlFor={disabled ? undefined : attachInputId}\n className={attachClassName}\n aria-label={attachAriaLabel}\n aria-disabled={disabled || undefined}\n data-testid=\"chat-composer-attach\"\n onMouseDown={stopPropagation}\n >\n <Icon name=\"attach_file\" size={24} />\n </label>\n ) : (\n <ChatIconButton\n edge=\"start\"\n aria-label={attachAriaLabel}\n data-testid=\"chat-composer-attach\"\n disabled={disabled}\n onClick={onAttachClick}\n onMouseDown={stopPropagation}\n >\n <Icon name=\"attach_file\" size={24} />\n </ChatIconButton>\n )\n ) : null;\n\n const sendButton = onSendMessage ? (\n <ChatIconButton\n edge=\"end\"\n color=\"primary\"\n aria-label={sendAriaLabel}\n data-testid=\"chat-composer-send\"\n disabled={!canSend}\n onClick={handleSend}\n onMouseDown={stopPropagation}\n >\n <Icon name=\"send\" size={24} />\n </ChatIconButton>\n ) : null;\n\n if (showAttach && !onSendMessage) {\n return (\n <div\n className={cn(\"smwb-chat-composer\", \"smwb-chat-composer_attach-only\", className)}\n data-testid=\"chat-composer\"\n >\n {attachButton}\n </div>\n );\n }\n\n if (!multiline) {\n return (\n <TextField\n className={cn(\"smwb-chat-composer\", className)}\n data-testid=\"chat-composer\"\n fullWidth\n value={value}\n disabled={disabled}\n placeholder={placeholder}\n onChange={(event) => setValue(event.target.value)}\n startAdornment={attachButton}\n endAdornment={sendButton}\n onKeyDown={handleKeyDown}\n />\n );\n }\n\n const onHolderMouseDown: React.MouseEventHandler<HTMLDivElement> = (event) => {\n if (textareaRef.current && event.currentTarget === event.target) {\n event.preventDefault();\n textareaRef.current.focus();\n }\n };\n\n return (\n <TextFieldWrapper\n className={cn(\"smwb-chat-composer\", className)}\n data-testid=\"chat-composer\"\n fullWidth\n disabled={disabled}\n isFilledState={value.length > 0}\n isFocused={isFocused}\n htmlFor={inputId}\n shrink={Boolean(attachButton)}\n onHolderMouseDown={onHolderMouseDown}\n startAdornment={attachButton}\n endAdornment={sendButton}\n >\n <textarea\n id={inputId}\n ref={textareaRef}\n className={cn(\n \"smwb-text-field__input\",\n \"smwb-chat-composer__input\",\n \"smwb-text-field__input--show-placeholder\",\n attachButton && \"smwb-text-field__input--adornment-start\",\n sendButton && \"smwb-text-field__input--adornment-end\"\n )}\n value={value}\n disabled={disabled}\n placeholder={placeholder}\n rows={1}\n onChange={(event) => setValue(event.target.value)}\n onFocus={() => setIsFocused(true)}\n onBlur={() => setIsFocused(false)}\n onKeyDown={handleKeyDown}\n />\n </TextFieldWrapper>\n );\n}\n\nexport default ChatComposer;\n"],"names":["stopPropagation","event","insertNewlineAtCursor","element","value","setValue","start","_a","end","_b","nextValue","ChatComposer","className","onSendMessage","placeholder","disabled","sendAriaLabel","shiftEnterNewline","ctrlEnterNewline","fileUpload","attachInputId","onAttachClick","attachAriaLabel","useState","isFocused","setIsFocused","inputId","useId","textareaRef","useRef","multiline","canSend","showAttach","handleSend","text","handleKeyDown","shouldComposerNewlineOnEnter","attachClassName","cn","attachButton","jsx","Icon","ChatIconButton","sendButton","TextField","onHolderMouseDown","TextFieldWrapper"],"mappings":"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"}
|
|
1
|
+
{"version":3,"file":"chatComposer.js","sources":["../../../../src/components/dataDisplay/chat/chatComposer.tsx"],"sourcesContent":["import React, { useId, useRef, useState } from \"react\";\nimport cn from \"clsx\";\nimport Icon from \"../../base/icon/icon\";\nimport { TextField } from \"../../inputs/textField\";\nimport { TextFieldWrapper } from \"../../inputs/textField/textFieldWrapper\";\nimport ChatIconButton from \"./chatIconButton\";\nimport { shouldComposerNewlineOnEnter } from \"./utils\";\n\n/**\n * Deprecated: the props of the old chat input. Use `ComposerProps` — `Chat` now draws a `Composer` as its footer,\n * and the standalone `Composer` replaces these props (`onSendMessage` → `onSend`, `sendAriaLabel` → `sendLabel`,\n * `attachAriaLabel` → `attachLabel`, `fileUpload` + `attachInputId`/`onAttachClick` → `onAttach`,\n * `shiftEnterNewline` → `sendKey=\"enter\"`; `ctrlEnterNewline` has no equivalent — Ctrl/⌘+Enter always sends).\n * Removed in the next major.\n *\n * @deprecated Use `Composer` (`ComposerProps`); see the README section \"Migrating from ChatComposer\".\n */\nexport interface ChatComposerProps {\n className?: string;\n onSendMessage?: (text: string) => void | Promise<void>;\n placeholder?: string;\n disabled?: boolean;\n sendAriaLabel?: string;\n shiftEnterNewline?: boolean;\n ctrlEnterNewline?: boolean;\n fileUpload?: boolean;\n attachInputId?: string;\n onAttachClick?: () => void;\n attachAriaLabel?: string;\n}\n\nfunction stopPropagation(event: React.SyntheticEvent) {\n event.stopPropagation();\n}\n\nfunction insertNewlineAtCursor(element: HTMLTextAreaElement, value: string, setValue: (next: string) => void) {\n const start = element.selectionStart ?? value.length;\n const end = element.selectionEnd ?? value.length;\n const nextValue = `${value.slice(0, start)}\\n${value.slice(end)}`;\n\n setValue(nextValue);\n\n requestAnimationFrame(() => {\n element.selectionStart = start + 1;\n element.selectionEnd = start + 1;\n });\n}\n\n/**\n * Deprecated: the old chat input — Enter sends, a TextField-based DOM and the `chat-composer*` test ids.\n * `Chat` draws a `Composer` as its footer now, and the standalone `Composer` replaces this component\n * (`onSendMessage` → `onSend`, Enter-to-send → `sendKey=\"enter\"`). Kept for the migration and removed in the\n * next major; to keep this markup inside a Chat while migrating, pass `legacyComposer` to `Chat`.\n *\n * @deprecated Use `Composer`; see the README section \"Migrating from ChatComposer\".\n */\nexport function ChatComposer({\n className,\n onSendMessage,\n placeholder = \"message\",\n disabled = false,\n sendAriaLabel = \"Send message\",\n shiftEnterNewline = true,\n ctrlEnterNewline = true,\n fileUpload = false,\n attachInputId,\n onAttachClick,\n attachAriaLabel = \"Attach file\",\n}: ChatComposerProps) {\n const [value, setValue] = useState(\"\");\n const [isFocused, setIsFocused] = useState(false);\n const inputId = useId();\n const textareaRef = useRef<HTMLTextAreaElement>(null);\n const multiline = shiftEnterNewline || ctrlEnterNewline;\n const canSend = Boolean(onSendMessage) && value.trim().length > 0 && !disabled;\n const showAttach = fileUpload && Boolean(attachInputId || onAttachClick);\n\n const handleSend = () => {\n if (!onSendMessage) {\n return;\n }\n\n const text = value.trim();\n\n if (!text || disabled) {\n return;\n }\n\n void onSendMessage(text);\n setValue(\"\");\n };\n\n const handleKeyDown = (event: React.KeyboardEvent<HTMLInputElement | HTMLTextAreaElement>) => {\n // Enter that commits or cancels an IME composition belongs to the IME, not to the composer.\n if (event.nativeEvent.isComposing || event.keyCode === 229) {\n return;\n }\n\n if (shouldComposerNewlineOnEnter(event, { shiftEnterNewline, ctrlEnterNewline })) {\n if (event.currentTarget instanceof HTMLTextAreaElement) {\n event.preventDefault();\n insertNewlineAtCursor(event.currentTarget, value, setValue);\n }\n\n return;\n }\n\n if (event.key !== \"Enter\") {\n return;\n }\n\n event.preventDefault();\n handleSend();\n };\n\n const attachClassName = cn(\n \"smwb-chat-icon-button\",\n \"smwb-chat-icon-button_edge-start\",\n disabled && \"smwb-chat-icon-button_disabled\"\n );\n\n const attachButton = showAttach ? (\n attachInputId ? (\n <label\n htmlFor={disabled ? undefined : attachInputId}\n className={attachClassName}\n aria-label={attachAriaLabel}\n aria-disabled={disabled || undefined}\n data-testid=\"chat-composer-attach\"\n onMouseDown={stopPropagation}\n >\n <Icon name=\"attach_file\" size={24} />\n </label>\n ) : (\n <ChatIconButton\n edge=\"start\"\n aria-label={attachAriaLabel}\n data-testid=\"chat-composer-attach\"\n disabled={disabled}\n onClick={onAttachClick}\n onMouseDown={stopPropagation}\n >\n <Icon name=\"attach_file\" size={24} />\n </ChatIconButton>\n )\n ) : null;\n\n const sendButton = onSendMessage ? (\n <ChatIconButton\n edge=\"end\"\n color=\"primary\"\n aria-label={sendAriaLabel}\n data-testid=\"chat-composer-send\"\n disabled={!canSend}\n onClick={handleSend}\n onMouseDown={stopPropagation}\n >\n <Icon name=\"send\" size={24} />\n </ChatIconButton>\n ) : null;\n\n if (showAttach && !onSendMessage) {\n return (\n <div\n className={cn(\"smwb-chat-composer\", \"smwb-chat-composer_attach-only\", className)}\n data-testid=\"chat-composer\"\n >\n {attachButton}\n </div>\n );\n }\n\n if (!multiline) {\n return (\n <TextField\n className={cn(\"smwb-chat-composer\", className)}\n data-testid=\"chat-composer\"\n fullWidth\n value={value}\n disabled={disabled}\n placeholder={placeholder}\n onChange={(event) => setValue(event.target.value)}\n startAdornment={attachButton}\n endAdornment={sendButton}\n onKeyDown={handleKeyDown}\n />\n );\n }\n\n const onHolderMouseDown: React.MouseEventHandler<HTMLDivElement> = (event) => {\n if (textareaRef.current && event.currentTarget === event.target) {\n event.preventDefault();\n textareaRef.current.focus();\n }\n };\n\n return (\n <TextFieldWrapper\n className={cn(\"smwb-chat-composer\", className)}\n data-testid=\"chat-composer\"\n fullWidth\n disabled={disabled}\n isFilledState={value.length > 0}\n isFocused={isFocused}\n htmlFor={inputId}\n shrink={Boolean(attachButton)}\n onHolderMouseDown={onHolderMouseDown}\n startAdornment={attachButton}\n endAdornment={sendButton}\n >\n <textarea\n id={inputId}\n ref={textareaRef}\n className={cn(\n \"smwb-text-field__input\",\n \"smwb-chat-composer__input\",\n \"smwb-text-field__input--show-placeholder\",\n attachButton && \"smwb-text-field__input--adornment-start\",\n sendButton && \"smwb-text-field__input--adornment-end\"\n )}\n value={value}\n disabled={disabled}\n placeholder={placeholder}\n rows={1}\n onChange={(event) => setValue(event.target.value)}\n onFocus={() => setIsFocused(true)}\n onBlur={() => setIsFocused(false)}\n onKeyDown={handleKeyDown}\n />\n </TextFieldWrapper>\n );\n}\n\nexport default ChatComposer;\n"],"names":["stopPropagation","event","insertNewlineAtCursor","element","value","setValue","start","_a","end","_b","nextValue","ChatComposer","className","onSendMessage","placeholder","disabled","sendAriaLabel","shiftEnterNewline","ctrlEnterNewline","fileUpload","attachInputId","onAttachClick","attachAriaLabel","useState","isFocused","setIsFocused","inputId","useId","textareaRef","useRef","multiline","canSend","showAttach","handleSend","text","handleKeyDown","shouldComposerNewlineOnEnter","attachClassName","cn","attachButton","jsx","Icon","ChatIconButton","sendButton","TextField","onHolderMouseDown","TextFieldWrapper"],"mappings":"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"}
|
|
@@ -3,7 +3,7 @@ export type { ChatLayoutProps, ChatLayoutChatProps } from "./chatLayout";
|
|
|
3
3
|
export { default as ChatOverlayLayout } from "./chatOverlayLayout";
|
|
4
4
|
export type { ChatOverlayLayoutProps, ChatOverlayLayoutChatProps } from "./chatOverlayLayout";
|
|
5
5
|
export { default as Chat } from "./chat";
|
|
6
|
-
export type { ChatProps } from "./chat";
|
|
6
|
+
export type { ChatProps, ChatFooterComposerProps } from "./chat";
|
|
7
7
|
export { default as ChatShell } from "./chatShell";
|
|
8
8
|
export type { ChatShellProps } from "./chatShell";
|
|
9
9
|
export { default as ChatHeader } from "./chatHeader";
|
|
@@ -14,10 +14,24 @@ export declare function shouldShowChatCloseButton(options: {
|
|
|
14
14
|
effectiveLayout?: ChatLayoutMode;
|
|
15
15
|
showCloseButton?: boolean;
|
|
16
16
|
}): boolean;
|
|
17
|
+
/**
|
|
18
|
+
* Deprecated: the newline flags of the old `ChatComposer`. `Composer` picks the send key with `sendKey` instead
|
|
19
|
+
* (`"enter"` = Enter sends, Shift+Enter makes a newline; `"modEnter"` = Ctrl/⌘+Enter sends). Removed with
|
|
20
|
+
* `ChatComposer` in the next major.
|
|
21
|
+
*
|
|
22
|
+
* @deprecated Use `Composer`'s `sendKey`; see the README section "Migrating from ChatComposer".
|
|
23
|
+
*/
|
|
17
24
|
export interface ChatComposerNewlineOptions {
|
|
18
25
|
shiftEnterNewline?: boolean;
|
|
19
26
|
ctrlEnterNewline?: boolean;
|
|
20
27
|
}
|
|
28
|
+
/**
|
|
29
|
+
* Deprecated: the key rule of the old `ChatComposer` (which Enter sends, which makes a newline).
|
|
30
|
+
* `Composer` resolves the same choice through `sendKey` in `resolveComposerKeyAction`, and `Chat` draws a `Composer`
|
|
31
|
+
* by default. Kept for `ChatComposer` and `legacyComposer` only; removed in the next major.
|
|
32
|
+
*
|
|
33
|
+
* @deprecated Use `Composer`'s `sendKey`; see the README section "Migrating from ChatComposer".
|
|
34
|
+
*/
|
|
21
35
|
export declare function shouldComposerNewlineOnEnter(event: {
|
|
22
36
|
key: string;
|
|
23
37
|
shiftKey: boolean;
|
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"utils.js","sources":["../../../../src/components/dataDisplay/chat/utils.ts"],"sourcesContent":["import {\n ChatAttachment,\n ChatLayoutMode,\n CHAT_EXPAND_LAYOUTS,\n CHAT_MESSAGE_DELIVERY_STATUSES,\n CHAT_MESSAGE_STATUS_ICONS,\n CHAT_MESSAGE_STATUS_LABELS,\n ChatMessageDeliveryStatus,\n ChatMessageStatus,\n ChatMessageStatusIcons,\n} from \"./types\";\n\nexport function isChatMessageDeliveryStatus(status: ChatMessageStatus): status is ChatMessageDeliveryStatus {\n return CHAT_MESSAGE_DELIVERY_STATUSES.includes(status as ChatMessageDeliveryStatus);\n}\n\nexport function resolveChatMessageStatusIcon(\n status: ChatMessageStatus,\n icons?: ChatMessageStatusIcons & Record<string, string | undefined>\n): string | undefined {\n const custom = icons?.[status];\n if (custom) {\n return custom;\n }\n\n if (isChatMessageDeliveryStatus(status)) {\n return CHAT_MESSAGE_STATUS_ICONS[status];\n }\n\n return undefined;\n}\n\nexport function resolveChatMessageStatusLabel(status: ChatMessageStatus): string {\n if (isChatMessageDeliveryStatus(status)) {\n return CHAT_MESSAGE_STATUS_LABELS[status];\n }\n\n return String(status);\n}\n\nexport function isImageAttachment(attachment: ChatAttachment): boolean {\n if (attachment.mimeType?.startsWith(\"image/\")) {\n return true;\n }\n\n return /\\.(png|jpe?g|gif|webp|bmp|svg)$/i.test(attachment.name);\n}\n\nexport function formatChatTimestamp(value?: string | Date): string {\n if (!value) {\n return \"\";\n }\n\n const date = value instanceof Date ? value : new Date(value);\n\n if (Number.isNaN(date.getTime())) {\n return String(value);\n }\n\n return new Intl.DateTimeFormat(undefined, {\n hour: \"2-digit\",\n minute: \"2-digit\",\n }).format(date);\n}\n\nexport function resolveAllowedLayouts(input?: ChatLayoutMode[]): ChatLayoutMode[] {\n if (input == null) {\n return [\"floating\"];\n }\n\n if (input.length === 0) {\n return [];\n }\n\n return CHAT_EXPAND_LAYOUTS.filter((mode) => input.includes(mode));\n}\n\nexport function pickInitialLayout(allowed: ChatLayoutMode[], preferred?: ChatLayoutMode): ChatLayoutMode {\n if (preferred && preferred !== \"closed\" && allowed.includes(preferred)) {\n return preferred;\n }\n\n return allowed[0] ?? \"floating\";\n}\n\nexport function getChatLayoutActions(\n allowedLayouts: ChatLayoutMode[],\n currentLayout?: ChatLayoutMode\n): Exclude<ChatLayoutMode, \"closed\">[] {\n return resolveAllowedLayouts(allowedLayouts).filter(\n (mode): mode is Exclude<ChatLayoutMode, \"closed\"> => mode !== \"closed\" && mode !== currentLayout\n );\n}\n\nexport function shouldShowChatCloseButton(options: {\n floatingTrigger?: boolean;\n embedded?: boolean;\n overlayContext?: boolean;\n effectiveLayout?: ChatLayoutMode;\n showCloseButton?: boolean;\n}): boolean {\n if (options.showCloseButton === false) {\n return false;\n }\n\n if (options.showCloseButton === true) {\n return true;\n }\n\n if (\n options.overlayContext &&\n options.floatingTrigger &&\n !options.embedded &&\n (options.effectiveLayout === \"floating\" || options.effectiveLayout === \"fullHeight\")\n ) {\n return true;\n }\n\n return Boolean(options.floatingTrigger && !options.embedded && options.effectiveLayout === \"floating\");\n}\n\nexport interface ChatComposerNewlineOptions {\n shiftEnterNewline?: boolean;\n ctrlEnterNewline?: boolean;\n}\n\nexport function shouldComposerNewlineOnEnter(\n event: { key: string; shiftKey: boolean; ctrlKey: boolean; metaKey: boolean },\n options: ChatComposerNewlineOptions = {}\n): boolean {\n if (event.key !== \"Enter\") {\n return false;\n }\n\n const { shiftEnterNewline = true, ctrlEnterNewline = true } = options;\n const isCtrl = event.ctrlKey || event.metaKey;\n\n if (shiftEnterNewline && event.shiftKey && !isCtrl) {\n return true;\n }\n\n if (ctrlEnterNewline && isCtrl && !event.shiftKey) {\n return true;\n }\n\n return false;\n}\n"],"names":["isChatMessageDeliveryStatus","status","CHAT_MESSAGE_DELIVERY_STATUSES","resolveChatMessageStatusIcon","icons","custom","CHAT_MESSAGE_STATUS_ICONS","resolveChatMessageStatusLabel","CHAT_MESSAGE_STATUS_LABELS","isImageAttachment","attachment","_a","formatChatTimestamp","value","date","resolveAllowedLayouts","input","CHAT_EXPAND_LAYOUTS","mode","pickInitialLayout","allowed","preferred","getChatLayoutActions","allowedLayouts","currentLayout","shouldShowChatCloseButton","options","shouldComposerNewlineOnEnter","event","shiftEnterNewline","ctrlEnterNewline","isCtrl"],"mappings":";AAYO,SAASA,EAA4BC,GAAgE;AAC1G,SAAOC,EAA+B,SAASD,CAAmC;AACpF;AAEO,SAASE,EACdF,GACAG,GACoB;AACpB,QAAMC,IAASD,KAAA,gBAAAA,EAAQH;AACvB,MAAII;AACF,WAAOA;AAGT,MAAIL,EAA4BC,CAAM;AACpC,WAAOK,EAA0BL,CAAM;AAI3C;AAEO,SAASM,EAA8BN,GAAmC;AAC/E,SAAID,EAA4BC,CAAM,IAC7BO,EAA2BP,CAAM,IAGnC,OAAOA,CAAM;AACtB;AAEO,SAASQ,EAAkBC,GAAqC;;AACrE,UAAIC,IAAAD,EAAW,aAAX,QAAAC,EAAqB,WAAW,YAC3B,KAGF,mCAAmC,KAAKD,EAAW,IAAI;AAChE;AAEO,SAASE,EAAoBC,GAA+B;AACjE,MAAI,CAACA;AACH,WAAO;AAGT,QAAMC,IAAOD,aAAiB,OAAOA,IAAQ,IAAI,KAAKA,CAAK;AAE3D,SAAI,OAAO,MAAMC,EAAK,QAAA,CAAS,IACtB,OAAOD,CAAK,IAGd,IAAI,KAAK,eAAe,QAAW;AAAA,IACxC,MAAM;AAAA,IACN,QAAQ;AAAA,EAAA,CACT,EAAE,OAAOC,CAAI;AAChB;AAEO,SAASC,EAAsBC,GAA4C;AAChF,SAAIA,KAAS,OACJ,CAAC,UAAU,IAGhBA,EAAM,WAAW,IACZ,CAAA,IAGFC,EAAoB,OAAO,CAACC,MAASF,EAAM,SAASE,CAAI,CAAC;AAClE;AAEO,SAASC,EAAkBC,GAA2BC,GAA4C;;AACvG,SAAIA,KAAaA,MAAc,YAAYD,EAAQ,SAASC,CAAS,IAC5DA,KAGFV,IAAAS,EAAQ,CAAC,MAAT,OAAAT,IAAc;AACvB;AAEO,SAASW,EACdC,GACAC,GACqC;AACrC,SAAOT,EAAsBQ,CAAc,EAAE;AAAA,IAC3C,CAACL,MAAoDA,MAAS,YAAYA,MAASM;AAAA,EAAA;AAEvF;AAEO,SAASC,EAA0BC,GAM9B;AACV,SAAIA,EAAQ,oBAAoB,KACvB,KAGLA,EAAQ,oBAAoB,MAK9BA,EAAQ,kBACRA,EAAQ,mBACR,CAACA,EAAQ,aACRA,EAAQ,oBAAoB,cAAcA,EAAQ,oBAAoB,gBAEhE,KAGF,GAAQA,EAAQ,mBAAmB,CAACA,EAAQ,YAAYA,EAAQ,oBAAoB;AAC7F;
|
|
1
|
+
{"version":3,"file":"utils.js","sources":["../../../../src/components/dataDisplay/chat/utils.ts"],"sourcesContent":["import {\n ChatAttachment,\n ChatLayoutMode,\n CHAT_EXPAND_LAYOUTS,\n CHAT_MESSAGE_DELIVERY_STATUSES,\n CHAT_MESSAGE_STATUS_ICONS,\n CHAT_MESSAGE_STATUS_LABELS,\n ChatMessageDeliveryStatus,\n ChatMessageStatus,\n ChatMessageStatusIcons,\n} from \"./types\";\n\nexport function isChatMessageDeliveryStatus(status: ChatMessageStatus): status is ChatMessageDeliveryStatus {\n return CHAT_MESSAGE_DELIVERY_STATUSES.includes(status as ChatMessageDeliveryStatus);\n}\n\nexport function resolveChatMessageStatusIcon(\n status: ChatMessageStatus,\n icons?: ChatMessageStatusIcons & Record<string, string | undefined>\n): string | undefined {\n const custom = icons?.[status];\n if (custom) {\n return custom;\n }\n\n if (isChatMessageDeliveryStatus(status)) {\n return CHAT_MESSAGE_STATUS_ICONS[status];\n }\n\n return undefined;\n}\n\nexport function resolveChatMessageStatusLabel(status: ChatMessageStatus): string {\n if (isChatMessageDeliveryStatus(status)) {\n return CHAT_MESSAGE_STATUS_LABELS[status];\n }\n\n return String(status);\n}\n\nexport function isImageAttachment(attachment: ChatAttachment): boolean {\n if (attachment.mimeType?.startsWith(\"image/\")) {\n return true;\n }\n\n return /\\.(png|jpe?g|gif|webp|bmp|svg)$/i.test(attachment.name);\n}\n\nexport function formatChatTimestamp(value?: string | Date): string {\n if (!value) {\n return \"\";\n }\n\n const date = value instanceof Date ? value : new Date(value);\n\n if (Number.isNaN(date.getTime())) {\n return String(value);\n }\n\n return new Intl.DateTimeFormat(undefined, {\n hour: \"2-digit\",\n minute: \"2-digit\",\n }).format(date);\n}\n\nexport function resolveAllowedLayouts(input?: ChatLayoutMode[]): ChatLayoutMode[] {\n if (input == null) {\n return [\"floating\"];\n }\n\n if (input.length === 0) {\n return [];\n }\n\n return CHAT_EXPAND_LAYOUTS.filter((mode) => input.includes(mode));\n}\n\nexport function pickInitialLayout(allowed: ChatLayoutMode[], preferred?: ChatLayoutMode): ChatLayoutMode {\n if (preferred && preferred !== \"closed\" && allowed.includes(preferred)) {\n return preferred;\n }\n\n return allowed[0] ?? \"floating\";\n}\n\nexport function getChatLayoutActions(\n allowedLayouts: ChatLayoutMode[],\n currentLayout?: ChatLayoutMode\n): Exclude<ChatLayoutMode, \"closed\">[] {\n return resolveAllowedLayouts(allowedLayouts).filter(\n (mode): mode is Exclude<ChatLayoutMode, \"closed\"> => mode !== \"closed\" && mode !== currentLayout\n );\n}\n\nexport function shouldShowChatCloseButton(options: {\n floatingTrigger?: boolean;\n embedded?: boolean;\n overlayContext?: boolean;\n effectiveLayout?: ChatLayoutMode;\n showCloseButton?: boolean;\n}): boolean {\n if (options.showCloseButton === false) {\n return false;\n }\n\n if (options.showCloseButton === true) {\n return true;\n }\n\n if (\n options.overlayContext &&\n options.floatingTrigger &&\n !options.embedded &&\n (options.effectiveLayout === \"floating\" || options.effectiveLayout === \"fullHeight\")\n ) {\n return true;\n }\n\n return Boolean(options.floatingTrigger && !options.embedded && options.effectiveLayout === \"floating\");\n}\n\n/**\n * Deprecated: the newline flags of the old `ChatComposer`. `Composer` picks the send key with `sendKey` instead\n * (`\"enter\"` = Enter sends, Shift+Enter makes a newline; `\"modEnter\"` = Ctrl/⌘+Enter sends). Removed with\n * `ChatComposer` in the next major.\n *\n * @deprecated Use `Composer`'s `sendKey`; see the README section \"Migrating from ChatComposer\".\n */\nexport interface ChatComposerNewlineOptions {\n shiftEnterNewline?: boolean;\n ctrlEnterNewline?: boolean;\n}\n\n/**\n * Deprecated: the key rule of the old `ChatComposer` (which Enter sends, which makes a newline).\n * `Composer` resolves the same choice through `sendKey` in `resolveComposerKeyAction`, and `Chat` draws a `Composer`\n * by default. Kept for `ChatComposer` and `legacyComposer` only; removed in the next major.\n *\n * @deprecated Use `Composer`'s `sendKey`; see the README section \"Migrating from ChatComposer\".\n */\nexport function shouldComposerNewlineOnEnter(\n event: { key: string; shiftKey: boolean; ctrlKey: boolean; metaKey: boolean },\n options: ChatComposerNewlineOptions = {}\n): boolean {\n if (event.key !== \"Enter\") {\n return false;\n }\n\n const { shiftEnterNewline = true, ctrlEnterNewline = true } = options;\n const isCtrl = event.ctrlKey || event.metaKey;\n\n if (shiftEnterNewline && event.shiftKey && !isCtrl) {\n return true;\n }\n\n if (ctrlEnterNewline && isCtrl && !event.shiftKey) {\n return true;\n }\n\n return false;\n}\n"],"names":["isChatMessageDeliveryStatus","status","CHAT_MESSAGE_DELIVERY_STATUSES","resolveChatMessageStatusIcon","icons","custom","CHAT_MESSAGE_STATUS_ICONS","resolveChatMessageStatusLabel","CHAT_MESSAGE_STATUS_LABELS","isImageAttachment","attachment","_a","formatChatTimestamp","value","date","resolveAllowedLayouts","input","CHAT_EXPAND_LAYOUTS","mode","pickInitialLayout","allowed","preferred","getChatLayoutActions","allowedLayouts","currentLayout","shouldShowChatCloseButton","options","shouldComposerNewlineOnEnter","event","shiftEnterNewline","ctrlEnterNewline","isCtrl"],"mappings":";AAYO,SAASA,EAA4BC,GAAgE;AAC1G,SAAOC,EAA+B,SAASD,CAAmC;AACpF;AAEO,SAASE,EACdF,GACAG,GACoB;AACpB,QAAMC,IAASD,KAAA,gBAAAA,EAAQH;AACvB,MAAII;AACF,WAAOA;AAGT,MAAIL,EAA4BC,CAAM;AACpC,WAAOK,EAA0BL,CAAM;AAI3C;AAEO,SAASM,EAA8BN,GAAmC;AAC/E,SAAID,EAA4BC,CAAM,IAC7BO,EAA2BP,CAAM,IAGnC,OAAOA,CAAM;AACtB;AAEO,SAASQ,EAAkBC,GAAqC;;AACrE,UAAIC,IAAAD,EAAW,aAAX,QAAAC,EAAqB,WAAW,YAC3B,KAGF,mCAAmC,KAAKD,EAAW,IAAI;AAChE;AAEO,SAASE,EAAoBC,GAA+B;AACjE,MAAI,CAACA;AACH,WAAO;AAGT,QAAMC,IAAOD,aAAiB,OAAOA,IAAQ,IAAI,KAAKA,CAAK;AAE3D,SAAI,OAAO,MAAMC,EAAK,QAAA,CAAS,IACtB,OAAOD,CAAK,IAGd,IAAI,KAAK,eAAe,QAAW;AAAA,IACxC,MAAM;AAAA,IACN,QAAQ;AAAA,EAAA,CACT,EAAE,OAAOC,CAAI;AAChB;AAEO,SAASC,EAAsBC,GAA4C;AAChF,SAAIA,KAAS,OACJ,CAAC,UAAU,IAGhBA,EAAM,WAAW,IACZ,CAAA,IAGFC,EAAoB,OAAO,CAACC,MAASF,EAAM,SAASE,CAAI,CAAC;AAClE;AAEO,SAASC,EAAkBC,GAA2BC,GAA4C;;AACvG,SAAIA,KAAaA,MAAc,YAAYD,EAAQ,SAASC,CAAS,IAC5DA,KAGFV,IAAAS,EAAQ,CAAC,MAAT,OAAAT,IAAc;AACvB;AAEO,SAASW,EACdC,GACAC,GACqC;AACrC,SAAOT,EAAsBQ,CAAc,EAAE;AAAA,IAC3C,CAACL,MAAoDA,MAAS,YAAYA,MAASM;AAAA,EAAA;AAEvF;AAEO,SAASC,EAA0BC,GAM9B;AACV,SAAIA,EAAQ,oBAAoB,KACvB,KAGLA,EAAQ,oBAAoB,MAK9BA,EAAQ,kBACRA,EAAQ,mBACR,CAACA,EAAQ,aACRA,EAAQ,oBAAoB,cAAcA,EAAQ,oBAAoB,gBAEhE,KAGF,GAAQA,EAAQ,mBAAmB,CAACA,EAAQ,YAAYA,EAAQ,oBAAoB;AAC7F;AAqBO,SAASC,EACdC,GACAF,IAAsC,IAC7B;AACT,MAAIE,EAAM,QAAQ;AAChB,WAAO;AAGT,QAAM,EAAE,mBAAAC,IAAoB,IAAM,kBAAAC,IAAmB,OAASJ,GACxDK,IAASH,EAAM,WAAWA,EAAM;AAMtC,SAJI,GAAAC,KAAqBD,EAAM,YAAY,CAACG,KAIxCD,KAAoBC,KAAU,CAACH,EAAM;AAK3C;"}
|
|
@@ -0,0 +1,74 @@
|
|
|
1
|
+
/** Which way the layers run: left to right, or top to bottom. */
|
|
2
|
+
export type DagDirection = "LR" | "TB";
|
|
3
|
+
export interface DagLayoutInputNode {
|
|
4
|
+
id: string;
|
|
5
|
+
width: number;
|
|
6
|
+
height: number;
|
|
7
|
+
}
|
|
8
|
+
export interface DagLayoutInputEdge {
|
|
9
|
+
/** `source->target` unless given. */
|
|
10
|
+
id?: string | undefined;
|
|
11
|
+
source: string;
|
|
12
|
+
target: string;
|
|
13
|
+
}
|
|
14
|
+
export interface DagLayoutInput {
|
|
15
|
+
nodes: readonly DagLayoutInputNode[];
|
|
16
|
+
edges: readonly DagLayoutInputEdge[];
|
|
17
|
+
/** "LR" by default. */
|
|
18
|
+
direction?: DagDirection | undefined;
|
|
19
|
+
/** The space between layers; 64 by default. */
|
|
20
|
+
rankGap?: number | undefined;
|
|
21
|
+
/** The space between nodes in a layer, and twice it between disconnected parts; 24 by default. */
|
|
22
|
+
nodeGap?: number | undefined;
|
|
23
|
+
/** Ordering sweeps (down and up count as one each); 8 by default. */
|
|
24
|
+
sweeps?: number | undefined;
|
|
25
|
+
/** Told what was dropped from the input: unknown ids, self-loops, duplicates. */
|
|
26
|
+
warn?: ((message: string) => void) | undefined;
|
|
27
|
+
}
|
|
28
|
+
export interface DagPoint {
|
|
29
|
+
x: number;
|
|
30
|
+
y: number;
|
|
31
|
+
}
|
|
32
|
+
export interface DagLayoutNode {
|
|
33
|
+
id: string;
|
|
34
|
+
/** The left edge. */
|
|
35
|
+
x: number;
|
|
36
|
+
/** The top edge. */
|
|
37
|
+
y: number;
|
|
38
|
+
width: number;
|
|
39
|
+
height: number;
|
|
40
|
+
/** The node's layer, 0 for the first. */
|
|
41
|
+
layer: number;
|
|
42
|
+
/** The node's place in its layer, 0 for the first (dummies included). */
|
|
43
|
+
order: number;
|
|
44
|
+
}
|
|
45
|
+
export interface DagLayoutEdge {
|
|
46
|
+
id: string;
|
|
47
|
+
source: string;
|
|
48
|
+
target: string;
|
|
49
|
+
/** From the source's side to the target's side, through the layers between. */
|
|
50
|
+
points: DagPoint[];
|
|
51
|
+
/** The edge closes a cycle and was drawn against the layer direction. */
|
|
52
|
+
reversed: boolean;
|
|
53
|
+
}
|
|
54
|
+
export interface DagLayoutResult {
|
|
55
|
+
/** Every node drawn, in input order. */
|
|
56
|
+
nodes: Map<string, DagLayoutNode>;
|
|
57
|
+
/** Every edge drawn, in input order. */
|
|
58
|
+
edges: DagLayoutEdge[];
|
|
59
|
+
width: number;
|
|
60
|
+
height: number;
|
|
61
|
+
}
|
|
62
|
+
/** The id an edge is drawn and highlighted by. */
|
|
63
|
+
export declare const dagEdgeId: (edge: DagLayoutInputEdge) => string;
|
|
64
|
+
/**
|
|
65
|
+
* Lays out a directed graph in layers. Never throws: unknown ids, self-loops
|
|
66
|
+
* and duplicates are dropped (and reported through `warn`), and the edges that
|
|
67
|
+
* close a cycle are drawn against the layer direction, marked `reversed`.
|
|
68
|
+
*/
|
|
69
|
+
export declare function dagLayout(input: DagLayoutInput): DagLayoutResult;
|
|
70
|
+
/**
|
|
71
|
+
* An SVG path through an edge's points: a smooth S-curve between layers, a
|
|
72
|
+
* straight line through the layers it skips.
|
|
73
|
+
*/
|
|
74
|
+
export declare function dagEdgePath(points: readonly DagPoint[], direction?: DagDirection): string;
|
|
@@ -0,0 +1,289 @@
|
|
|
1
|
+
const _ = (o) => {
|
|
2
|
+
var l;
|
|
3
|
+
return (l = o.id) != null ? l : `${o.source}->${o.target}`;
|
|
4
|
+
};
|
|
5
|
+
function G(o) {
|
|
6
|
+
var a;
|
|
7
|
+
const l = (a = o.warn) != null ? a : (() => {
|
|
8
|
+
}), i = [], f = /* @__PURE__ */ new Map();
|
|
9
|
+
for (const n of o.nodes) {
|
|
10
|
+
if (f.has(n.id)) {
|
|
11
|
+
l(`node "${n.id}" is listed twice; the second is dropped.`);
|
|
12
|
+
continue;
|
|
13
|
+
}
|
|
14
|
+
f.set(n.id, i.length), i.push(n);
|
|
15
|
+
}
|
|
16
|
+
const h = [], e = /* @__PURE__ */ new Set(), c = /* @__PURE__ */ new Set();
|
|
17
|
+
for (const n of o.edges) {
|
|
18
|
+
const d = f.get(n.source), x = f.get(n.target);
|
|
19
|
+
if (d === void 0 || x === void 0) {
|
|
20
|
+
const M = d === void 0 ? n.source : n.target;
|
|
21
|
+
l(`edge ${n.source} -> ${n.target} names an unknown node "${M}"; it is dropped.`);
|
|
22
|
+
continue;
|
|
23
|
+
}
|
|
24
|
+
if (d === x) {
|
|
25
|
+
l(`edge ${n.source} -> ${n.target} is a self-loop; it is dropped.`);
|
|
26
|
+
continue;
|
|
27
|
+
}
|
|
28
|
+
const y = `${d} ${x}`, w = _(n);
|
|
29
|
+
if (e.has(y) || c.has(w)) {
|
|
30
|
+
l(`edge ${n.source} -> ${n.target} is listed twice; the second is dropped.`);
|
|
31
|
+
continue;
|
|
32
|
+
}
|
|
33
|
+
e.add(y), c.add(w), h.push({ id: w, source: n.source, target: n.target, from: d, to: x, reversed: !1 });
|
|
34
|
+
}
|
|
35
|
+
const s = i.map(() => []);
|
|
36
|
+
h.forEach((n, d) => s[n.from].push(d));
|
|
37
|
+
const t = new Uint8Array(i.length);
|
|
38
|
+
for (let n = 0; n < i.length; n++) {
|
|
39
|
+
if (t[n]) continue;
|
|
40
|
+
const d = [[n, 0]];
|
|
41
|
+
for (t[n] = 1; d.length; ) {
|
|
42
|
+
const x = d[d.length - 1], [y, w] = x, M = s[y];
|
|
43
|
+
if (w >= M.length) {
|
|
44
|
+
t[y] = 2, d.pop();
|
|
45
|
+
continue;
|
|
46
|
+
}
|
|
47
|
+
x[1] = w + 1;
|
|
48
|
+
const S = h[M[w]];
|
|
49
|
+
t[S.to] === 1 ? S.reversed = !0 : t[S.to] === 0 && (t[S.to] = 1, d.push([S.to, 0]));
|
|
50
|
+
}
|
|
51
|
+
}
|
|
52
|
+
return { nodes: i, index: f, edges: h };
|
|
53
|
+
}
|
|
54
|
+
function N(o, l) {
|
|
55
|
+
const i = Array.from({ length: o }, () => []), f = new Array(o).fill(0);
|
|
56
|
+
for (const [t, a] of l)
|
|
57
|
+
i[t].push(a), f[a]++;
|
|
58
|
+
const h = f.map((t) => t > 0), e = new Array(o).fill(0), c = [], s = [];
|
|
59
|
+
for (let t = 0; t < o; t++) f[t] === 0 && s.push(t);
|
|
60
|
+
for (let t = 0; t < s.length; t++) {
|
|
61
|
+
const a = s[t];
|
|
62
|
+
c.push(a);
|
|
63
|
+
for (const n of i[a])
|
|
64
|
+
e[n] = Math.max(e[n], e[a] + 1), --f[n] === 0 && s.push(n);
|
|
65
|
+
}
|
|
66
|
+
for (let t = c.length - 1; t >= 0; t--) {
|
|
67
|
+
const a = c[t], n = i[a];
|
|
68
|
+
n.length === 0 || h[a] || (e[a] = Math.min(...n.map((d) => e[d])) - 1);
|
|
69
|
+
}
|
|
70
|
+
return e;
|
|
71
|
+
}
|
|
72
|
+
function O(o, l, i) {
|
|
73
|
+
const f = [];
|
|
74
|
+
for (const s of o) for (const t of l[s].succs) f.push([i[s], i[t]]);
|
|
75
|
+
f.sort((s, t) => s[0] - t[0] || s[1] - t[1]);
|
|
76
|
+
let h = 1;
|
|
77
|
+
for (const [, s] of f) h = Math.max(h, s + 2);
|
|
78
|
+
const e = new Int32Array(h + 1);
|
|
79
|
+
let c = 0;
|
|
80
|
+
for (let s = f.length - 1; s >= 0; s--) {
|
|
81
|
+
const t = f[s][1];
|
|
82
|
+
for (let a = t; a > 0; a -= a & -a) c += e[a];
|
|
83
|
+
for (let a = t + 1; a <= h; a += a & -a) e[a]++;
|
|
84
|
+
}
|
|
85
|
+
return c;
|
|
86
|
+
}
|
|
87
|
+
function P(o, l, i) {
|
|
88
|
+
let f = 0;
|
|
89
|
+
for (let h = 0; h + 1 < o.length; h++) f += O(o[h], l, i);
|
|
90
|
+
return f;
|
|
91
|
+
}
|
|
92
|
+
function R(o, l, i, f) {
|
|
93
|
+
const h = /* @__PURE__ */ new Map();
|
|
94
|
+
for (const e of o) {
|
|
95
|
+
const c = f ? l[e].preds : l[e].succs;
|
|
96
|
+
c.length === 0 ? h.set(e, i[e]) : h.set(e, c.reduce((s, t) => s + i[t], 0) / c.length);
|
|
97
|
+
}
|
|
98
|
+
o.sort((e, c) => h.get(e) - h.get(c) || i[e] - i[c]), o.forEach((e, c) => i[e] = c);
|
|
99
|
+
}
|
|
100
|
+
function j(o, l, i) {
|
|
101
|
+
const f = new Int32Array(l.length);
|
|
102
|
+
for (const s of o) s.forEach((t, a) => f[t] = a);
|
|
103
|
+
let h = o.map((s) => s.slice()), e = P(o, l, f), c = 0;
|
|
104
|
+
for (let s = 0; s < i && e > 0; s++) {
|
|
105
|
+
if (s % 2 === 0) for (let n = 1; n < o.length; n++) R(o[n], l, f, !0);
|
|
106
|
+
else for (let n = o.length - 2; n >= 0; n--) R(o[n], l, f, !1);
|
|
107
|
+
const a = P(o, l, f);
|
|
108
|
+
if (a < e)
|
|
109
|
+
e = a, h = o.map((n) => n.slice()), c = 0;
|
|
110
|
+
else if (++c >= 2) break;
|
|
111
|
+
}
|
|
112
|
+
h.forEach((s, t) => o[t] = s);
|
|
113
|
+
}
|
|
114
|
+
function B(o, l, i) {
|
|
115
|
+
const f = [0];
|
|
116
|
+
for (let c = 1; c < o.length; c++) f.push(f[c - 1] + l[c - 1]);
|
|
117
|
+
const h = [];
|
|
118
|
+
o.forEach((c, s) => {
|
|
119
|
+
let t = { value: c - f[s], weight: i[s], count: 1 };
|
|
120
|
+
for (; h.length && h[h.length - 1].value > t.value; ) {
|
|
121
|
+
const a = h.pop(), n = a.weight + t.weight;
|
|
122
|
+
t = {
|
|
123
|
+
value: (a.value * a.weight + t.value * t.weight) / n,
|
|
124
|
+
weight: n,
|
|
125
|
+
count: a.count + t.count
|
|
126
|
+
};
|
|
127
|
+
}
|
|
128
|
+
h.push(t);
|
|
129
|
+
});
|
|
130
|
+
const e = [];
|
|
131
|
+
for (const c of h) for (let s = 0; s < c.count; s++) e.push(c.value + f[e.length]);
|
|
132
|
+
return e;
|
|
133
|
+
}
|
|
134
|
+
function F(o, l, i) {
|
|
135
|
+
const f = (e, c) => {
|
|
136
|
+
const s = l[e], t = l[c], a = s.node < 0 && t.node < 0 ? i / 2 : i;
|
|
137
|
+
return s.crossSize / 2 + a + t.crossSize / 2;
|
|
138
|
+
};
|
|
139
|
+
for (const e of o) {
|
|
140
|
+
let c = 0;
|
|
141
|
+
e.forEach((s, t) => {
|
|
142
|
+
t > 0 && (c += f(e[t - 1], s)), l[s].cross = c;
|
|
143
|
+
});
|
|
144
|
+
}
|
|
145
|
+
const h = ["down", "up", "down", "up", "both", "both"];
|
|
146
|
+
for (const e of h) {
|
|
147
|
+
const c = e === "up" ? o.map((s, t) => o.length - 1 - t) : o.map((s, t) => t);
|
|
148
|
+
for (const s of c) {
|
|
149
|
+
const t = o[s];
|
|
150
|
+
if (t.length === 0) continue;
|
|
151
|
+
const a = t.map((x) => {
|
|
152
|
+
const y = l[x], w = e === "down" ? y.preds : e === "up" ? y.succs : [...y.preds, ...y.succs];
|
|
153
|
+
return w.length === 0 ? y.cross : w.reduce((M, S) => M + l[S].cross, 0) / w.length;
|
|
154
|
+
}), n = t.slice(1).map((x, y) => f(t[y], x)), d = t.map((x) => l[x].node < 0 ? 2 : 1);
|
|
155
|
+
B(a, n, d).forEach((x, y) => l[t[y]].cross = x);
|
|
156
|
+
}
|
|
157
|
+
}
|
|
158
|
+
}
|
|
159
|
+
function q(o, l, i, f, h, e, c, s) {
|
|
160
|
+
const t = /* @__PURE__ */ new Map();
|
|
161
|
+
o.forEach((g, p) => t.set(g, p));
|
|
162
|
+
const a = i.map((g) => {
|
|
163
|
+
const p = l.edges[g], $ = t.get(p.from), r = t.get(p.to);
|
|
164
|
+
return p.reversed ? [r, $] : [$, r];
|
|
165
|
+
}), n = N(o.length, a), d = o.map((g, p) => ({
|
|
166
|
+
node: g,
|
|
167
|
+
rankSize: f(g),
|
|
168
|
+
crossSize: h(g),
|
|
169
|
+
layer: n[p],
|
|
170
|
+
cross: 0,
|
|
171
|
+
preds: [],
|
|
172
|
+
succs: []
|
|
173
|
+
})), x = i.map((g, p) => {
|
|
174
|
+
const [$, r] = a[p], u = [$];
|
|
175
|
+
let m = $;
|
|
176
|
+
for (let k = d[$].layer + 1; k < d[r].layer; k++) {
|
|
177
|
+
const E = d.length;
|
|
178
|
+
d.push({ node: -1, rankSize: 0, crossSize: 0, layer: k, cross: 0, preds: [], succs: [] }), d[m].succs.push(E), d[E].preds.push(m), u.push(E), m = E;
|
|
179
|
+
}
|
|
180
|
+
return d[m].succs.push(r), d[r].preds.push(m), u.push(r), { edge: g, chain: u };
|
|
181
|
+
}), y = d.reduce((g, p) => Math.max(g, p.layer + 1), 0), w = Array.from({ length: y }, () => []);
|
|
182
|
+
d.forEach((g, p) => w[g.layer].push(p)), j(w, d, s), F(w, d, c);
|
|
183
|
+
const M = w.map((g) => g.reduce((p, $) => Math.max(p, d[$].rankSize), 0)), S = [];
|
|
184
|
+
let A = 0;
|
|
185
|
+
M.forEach((g, p) => {
|
|
186
|
+
S[p] = A, A += g + (p + 1 < M.length ? e : 0);
|
|
187
|
+
});
|
|
188
|
+
let v = 1 / 0, z = -1 / 0;
|
|
189
|
+
for (const g of d)
|
|
190
|
+
v = Math.min(v, g.cross - g.crossSize / 2), z = Math.max(z, g.cross + g.crossSize / 2);
|
|
191
|
+
const I = Number.isFinite(v) ? -v : 0, C = /* @__PURE__ */ new Map();
|
|
192
|
+
w.forEach(
|
|
193
|
+
(g, p) => g.forEach(($, r) => {
|
|
194
|
+
const u = d[$];
|
|
195
|
+
u.node < 0 || C.set(u.node, {
|
|
196
|
+
rank: S[p] + (M[p] - u.rankSize) / 2,
|
|
197
|
+
cross: u.cross - u.crossSize / 2 + I,
|
|
198
|
+
layer: p,
|
|
199
|
+
order: r
|
|
200
|
+
});
|
|
201
|
+
})
|
|
202
|
+
);
|
|
203
|
+
const L = /* @__PURE__ */ new Map();
|
|
204
|
+
for (const { edge: g, chain: p } of x) {
|
|
205
|
+
const $ = [];
|
|
206
|
+
p.forEach((r, u) => {
|
|
207
|
+
const m = d[r], k = m.layer, E = m.cross + I, b = S[k] + (M[k] - m.rankSize) / 2;
|
|
208
|
+
u === 0 ? $.push({ rank: b + m.rankSize, cross: E }) : u === p.length - 1 ? $.push({ rank: b, cross: E }) : $.push({ rank: S[k], cross: E }, { rank: S[k] + M[k], cross: E });
|
|
209
|
+
}), l.edges[g].reversed && $.reverse(), L.set(g, $);
|
|
210
|
+
}
|
|
211
|
+
return {
|
|
212
|
+
nodes: C,
|
|
213
|
+
edges: L,
|
|
214
|
+
rankExtent: A,
|
|
215
|
+
crossExtent: Number.isFinite(z) ? z - v : 0
|
|
216
|
+
};
|
|
217
|
+
}
|
|
218
|
+
function D(o) {
|
|
219
|
+
var L, g, p, $;
|
|
220
|
+
const l = (L = o.direction) != null ? L : "LR", i = (g = o.rankGap) != null ? g : 64, f = (p = o.nodeGap) != null ? p : 24, h = ($ = o.sweeps) != null ? $ : 8, e = G(o), c = l === "LR", s = (r) => c ? e.nodes[r].width : e.nodes[r].height, t = (r) => c ? e.nodes[r].height : e.nodes[r].width, a = e.nodes.map((r, u) => u), n = (r) => {
|
|
221
|
+
for (; a[r] !== r; )
|
|
222
|
+
a[r] = a[a[r]], r = a[r];
|
|
223
|
+
return r;
|
|
224
|
+
};
|
|
225
|
+
for (const r of e.edges) {
|
|
226
|
+
const u = n(r.from), m = n(r.to);
|
|
227
|
+
u !== m && (a[Math.max(u, m)] = Math.min(u, m));
|
|
228
|
+
}
|
|
229
|
+
const d = /* @__PURE__ */ new Map();
|
|
230
|
+
e.nodes.forEach((r, u) => {
|
|
231
|
+
const m = n(u);
|
|
232
|
+
d.has(m) || d.set(m, { members: [], edges: [] }), d.get(m).members.push(u);
|
|
233
|
+
}), e.edges.forEach((r, u) => d.get(n(r.from)).edges.push(u));
|
|
234
|
+
const x = /* @__PURE__ */ new Map(), y = /* @__PURE__ */ new Map(), w = (r, u) => c ? { x: r, y: u } : { x: u, y: r };
|
|
235
|
+
let M = 0, S = 0;
|
|
236
|
+
for (const r of d.values()) {
|
|
237
|
+
const u = q(r.members, e, r.edges, s, t, i, f, h);
|
|
238
|
+
for (const [m, k] of u.nodes) {
|
|
239
|
+
const E = e.nodes[m];
|
|
240
|
+
x.set(m, {
|
|
241
|
+
id: E.id,
|
|
242
|
+
...w(k.rank, k.cross + M),
|
|
243
|
+
width: E.width,
|
|
244
|
+
height: E.height,
|
|
245
|
+
layer: k.layer,
|
|
246
|
+
order: k.order
|
|
247
|
+
});
|
|
248
|
+
}
|
|
249
|
+
for (const [m, k] of u.edges)
|
|
250
|
+
y.set(
|
|
251
|
+
m,
|
|
252
|
+
k.map((E) => w(E.rank, E.cross + M))
|
|
253
|
+
);
|
|
254
|
+
S = Math.max(S, u.rankExtent), M += u.crossExtent + f * 2;
|
|
255
|
+
}
|
|
256
|
+
const A = Math.max(0, M - f * 2), v = /* @__PURE__ */ new Map();
|
|
257
|
+
e.nodes.forEach((r, u) => v.set(r.id, x.get(u)));
|
|
258
|
+
const z = new Set(e.edges.map((r) => `${r.from} ${r.to}`)), I = e.edges.map((r, u) => {
|
|
259
|
+
let m = y.get(u);
|
|
260
|
+
if (r.reversed && z.has(`${r.to} ${r.from}`)) {
|
|
261
|
+
const k = (b) => c ? e.nodes[b].height : e.nodes[b].width, E = Math.min(8, k(r.from) / 4, k(r.to) / 4);
|
|
262
|
+
m = m.map((b) => c ? { x: b.x, y: b.y + E } : { x: b.x + E, y: b.y });
|
|
263
|
+
}
|
|
264
|
+
return { id: r.id, source: r.source, target: r.target, points: m, reversed: r.reversed };
|
|
265
|
+
}), C = w(S, A);
|
|
266
|
+
return { nodes: v, edges: I, width: C.x, height: C.y };
|
|
267
|
+
}
|
|
268
|
+
function U(o, l = "LR") {
|
|
269
|
+
if (o.length === 0) return "";
|
|
270
|
+
const i = (e) => Math.round(e * 10) / 10, f = o[0];
|
|
271
|
+
let h = `M${i(f.x)},${i(f.y)}`;
|
|
272
|
+
for (let e = 1; e < o.length; e++) {
|
|
273
|
+
const c = o[e - 1], s = o[e];
|
|
274
|
+
if (l === "LR") {
|
|
275
|
+
const t = (c.x + s.x) / 2;
|
|
276
|
+
h += ` C${i(t)},${i(c.y)} ${i(t)},${i(s.y)} ${i(s.x)},${i(s.y)}`;
|
|
277
|
+
} else {
|
|
278
|
+
const t = (c.y + s.y) / 2;
|
|
279
|
+
h += ` C${i(c.x)},${i(t)} ${i(s.x)},${i(t)} ${i(s.x)},${i(s.y)}`;
|
|
280
|
+
}
|
|
281
|
+
}
|
|
282
|
+
return h;
|
|
283
|
+
}
|
|
284
|
+
export {
|
|
285
|
+
_ as dagEdgeId,
|
|
286
|
+
U as dagEdgePath,
|
|
287
|
+
D as dagLayout
|
|
288
|
+
};
|
|
289
|
+
//# sourceMappingURL=dagLayout.js.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"dagLayout.js","sources":["../../../../src/components/dataDisplay/dagView/dagLayout.ts"],"sourcesContent":["// A layered (Sugiyama-style) layout for directed graphs: pure, synchronous and\n// deterministic, with no imports from Solid or the DOM, so the server and the\n// browser compute the same picture and a React port can copy the file as is.\n//\n// Steps: normalise the input; reverse the back edges of cycles; put each node\n// in a layer by the longest path from the sources; split edges that span\n// several layers with dummy points; order each layer by barycenter sweeps to\n// cut crossings; place nodes along the layer, pulled toward their neighbours\n// without overlapping; lay disconnected parts side by side; route each edge as\n// a list of points through its dummies.\n\n/** Which way the layers run: left to right, or top to bottom. */\nexport type DagDirection = \"LR\" | \"TB\";\n\nexport interface DagLayoutInputNode {\n id: string;\n width: number;\n height: number;\n}\n\nexport interface DagLayoutInputEdge {\n /** `source->target` unless given. */\n id?: string | undefined;\n source: string;\n target: string;\n}\n\nexport interface DagLayoutInput {\n nodes: readonly DagLayoutInputNode[];\n edges: readonly DagLayoutInputEdge[];\n /** \"LR\" by default. */\n direction?: DagDirection | undefined;\n /** The space between layers; 64 by default. */\n rankGap?: number | undefined;\n /** The space between nodes in a layer, and twice it between disconnected parts; 24 by default. */\n nodeGap?: number | undefined;\n /** Ordering sweeps (down and up count as one each); 8 by default. */\n sweeps?: number | undefined;\n /** Told what was dropped from the input: unknown ids, self-loops, duplicates. */\n warn?: ((message: string) => void) | undefined;\n}\n\nexport interface DagPoint {\n x: number;\n y: number;\n}\n\nexport interface DagLayoutNode {\n id: string;\n /** The left edge. */\n x: number;\n /** The top edge. */\n y: number;\n width: number;\n height: number;\n /** The node's layer, 0 for the first. */\n layer: number;\n /** The node's place in its layer, 0 for the first (dummies included). */\n order: number;\n}\n\nexport interface DagLayoutEdge {\n id: string;\n source: string;\n target: string;\n /** From the source's side to the target's side, through the layers between. */\n points: DagPoint[];\n /** The edge closes a cycle and was drawn against the layer direction. */\n reversed: boolean;\n}\n\nexport interface DagLayoutResult {\n /** Every node drawn, in input order. */\n nodes: Map<string, DagLayoutNode>;\n /** Every edge drawn, in input order. */\n edges: DagLayoutEdge[];\n width: number;\n height: number;\n}\n\n/** The id an edge is drawn and highlighted by. */\nexport const dagEdgeId = (edge: DagLayoutInputEdge): string => edge.id ?? `${edge.source}->${edge.target}`;\n\ninterface Vertex {\n /** Index into the real nodes, or -1 for a dummy. */\n node: number;\n /** Size along the layer axis (width in LR) and across it. */\n rankSize: number;\n crossSize: number;\n layer: number;\n /** Centre across the layer axis. */\n cross: number;\n preds: number[];\n succs: number[];\n}\n\ninterface Segment {\n /** The edge's index in the normalised list. */\n edge: number;\n /** Vertices from the layered source to the layered target, dummies between. */\n chain: number[];\n}\n\n// ---- Steps 1-2: normalise, break cycles ----\n\ninterface Normalised {\n nodes: DagLayoutInputNode[];\n index: Map<string, number>;\n edges: Array<{ id: string; source: string; target: string; from: number; to: number; reversed: boolean }>;\n}\n\nfunction normalise(input: DagLayoutInput): Normalised {\n const warn = input.warn ?? (() => undefined);\n const nodes: DagLayoutInputNode[] = [];\n const index = new Map<string, number>();\n for (const node of input.nodes) {\n if (index.has(node.id)) {\n warn(`node \"${node.id}\" is listed twice; the second is dropped.`);\n continue;\n }\n index.set(node.id, nodes.length);\n nodes.push(node);\n }\n const edges: Normalised[\"edges\"] = [];\n const pairs = new Set<string>();\n const ids = new Set<string>();\n for (const edge of input.edges) {\n const from = index.get(edge.source);\n const to = index.get(edge.target);\n if (from === undefined || to === undefined) {\n const missing = from === undefined ? edge.source : edge.target;\n warn(`edge ${edge.source} -> ${edge.target} names an unknown node \"${missing}\"; it is dropped.`);\n continue;\n }\n if (from === to) {\n warn(`edge ${edge.source} -> ${edge.target} is a self-loop; it is dropped.`);\n continue;\n }\n const pair = `${from} ${to}`;\n const id = dagEdgeId(edge);\n if (pairs.has(pair) || ids.has(id)) {\n warn(`edge ${edge.source} -> ${edge.target} is listed twice; the second is dropped.`);\n continue;\n }\n pairs.add(pair);\n ids.add(id);\n edges.push({ id, source: edge.source, target: edge.target, from, to, reversed: false });\n }\n\n // A depth-first walk in input order: an edge to a node still on the stack\n // closes a cycle, and is turned around so the rest can be layered.\n const out: number[][] = nodes.map(() => []);\n edges.forEach((edge, i) => out[edge.from].push(i));\n const state = new Uint8Array(nodes.length); // 0 new, 1 on the stack, 2 done\n for (let root = 0; root < nodes.length; root++) {\n if (state[root]) continue;\n const stack: Array<[number, number]> = [[root, 0]];\n state[root] = 1;\n while (stack.length) {\n const top = stack[stack.length - 1];\n const [v, next] = top;\n const list = out[v];\n if (next >= list.length) {\n state[v] = 2;\n stack.pop();\n continue;\n }\n top[1] = next + 1;\n const edge = edges[list[next]];\n if (state[edge.to] === 1) edge.reversed = true;\n else if (state[edge.to] === 0) {\n state[edge.to] = 1;\n stack.push([edge.to, 0]);\n }\n }\n }\n return { nodes, index, edges };\n}\n\n// ---- Step 3: layers by the longest path ----\n\nfunction assignLayers(count: number, arcs: Array<[number, number]>): number[] {\n const out: number[][] = Array.from({ length: count }, () => []);\n const inDegree = new Array<number>(count).fill(0);\n for (const [u, v] of arcs) {\n out[u].push(v);\n inDegree[v]++;\n }\n const hasPred = inDegree.map((d) => d > 0);\n const layer = new Array<number>(count).fill(0);\n const order: number[] = [];\n const queue: number[] = [];\n for (let v = 0; v < count; v++) if (inDegree[v] === 0) queue.push(v);\n for (let head = 0; head < queue.length; head++) {\n const u = queue[head];\n order.push(u);\n for (const v of out[u]) {\n layer[v] = Math.max(layer[v], layer[u] + 1);\n if (--inDegree[v] === 0) queue.push(v);\n }\n }\n // A source sits just before the first layer it feeds, not in layer 0 with a\n // long edge across: a late input stays next to the step that reads it.\n for (let i = order.length - 1; i >= 0; i--) {\n const v = order[i];\n const succs = out[v];\n if (succs.length === 0 || hasPred[v]) continue;\n layer[v] = Math.min(...succs.map((s) => layer[s])) - 1;\n }\n return layer;\n}\n\n// ---- Step 5: ordering ----\n\n/** Crossings between two neighbouring layers, by counting inversions. */\nfunction crossingsBetween(upper: number[], vertices: Vertex[], position: Int32Array): number {\n const pairs: Array<[number, number]> = [];\n for (const u of upper) for (const v of vertices[u].succs) pairs.push([position[u], position[v]]);\n pairs.sort((a, b) => a[0] - b[0] || a[1] - b[1]);\n // Inversions of the lower ends, with a Fenwick tree.\n let size = 1;\n for (const [, b] of pairs) size = Math.max(size, b + 2);\n const tree = new Int32Array(size + 1);\n let crossings = 0;\n for (let i = pairs.length - 1; i >= 0; i--) {\n const b = pairs[i][1];\n for (let j = b; j > 0; j -= j & -j) crossings += tree[j];\n for (let j = b + 1; j <= size; j += j & -j) tree[j]++;\n }\n return crossings;\n}\n\nfunction totalCrossings(layers: number[][], vertices: Vertex[], position: Int32Array): number {\n let sum = 0;\n for (let l = 0; l + 1 < layers.length; l++) sum += crossingsBetween(layers[l], vertices, position);\n return sum;\n}\n\nfunction reorder(layer: number[], vertices: Vertex[], position: Int32Array, down: boolean): void {\n const key = new Map<number, number>();\n for (const v of layer) {\n const neighbours = down ? vertices[v].preds : vertices[v].succs;\n if (neighbours.length === 0) key.set(v, position[v]);\n else key.set(v, neighbours.reduce((sum, n) => sum + position[n], 0) / neighbours.length);\n }\n // Ties keep the current order, so the result is the same on every run.\n layer.sort((a, b) => key.get(a)! - key.get(b)! || position[a] - position[b]);\n layer.forEach((v, i) => (position[v] = i));\n}\n\nfunction orderLayers(layers: number[][], vertices: Vertex[], sweeps: number): void {\n const position = new Int32Array(vertices.length);\n for (const layer of layers) layer.forEach((v, i) => (position[v] = i));\n let best = layers.map((layer) => layer.slice());\n let bestCrossings = totalCrossings(layers, vertices, position);\n let stale = 0;\n for (let sweep = 0; sweep < sweeps && bestCrossings > 0; sweep++) {\n const down = sweep % 2 === 0;\n if (down) for (let l = 1; l < layers.length; l++) reorder(layers[l], vertices, position, true);\n else for (let l = layers.length - 2; l >= 0; l--) reorder(layers[l], vertices, position, false);\n const crossings = totalCrossings(layers, vertices, position);\n if (crossings < bestCrossings) {\n bestCrossings = crossings;\n best = layers.map((layer) => layer.slice());\n stale = 0;\n } else if (++stale >= 2) break;\n }\n best.forEach((layer, l) => (layers[l] = layer));\n}\n\n// ---- Step 6: positions across the layer ----\n\n/**\n * Centres as close to `desired` as they can get, in order, at least `gap`\n * apart: an isotonic regression by pooling adjacent violators.\n */\nfunction place(desired: number[], gaps: number[], weights: number[]): number[] {\n // Shift out the gaps, so the constraint becomes \"non-decreasing\".\n const offset: number[] = [0];\n for (let i = 1; i < desired.length; i++) offset.push(offset[i - 1] + gaps[i - 1]);\n const blocks: Array<{ value: number; weight: number; count: number }> = [];\n desired.forEach((d, i) => {\n let block = { value: d - offset[i], weight: weights[i], count: 1 };\n while (blocks.length && blocks[blocks.length - 1].value > block.value) {\n const last = blocks.pop()!;\n const weight = last.weight + block.weight;\n block = {\n value: (last.value * last.weight + block.value * block.weight) / weight,\n weight,\n count: last.count + block.count,\n };\n }\n blocks.push(block);\n });\n const result: number[] = [];\n for (const block of blocks) for (let k = 0; k < block.count; k++) result.push(block.value + offset[result.length]);\n return result;\n}\n\nfunction assignCross(layers: number[][], vertices: Vertex[], nodeGap: number): void {\n const gapBetween = (a: number, b: number): number => {\n const va = vertices[a];\n const vb = vertices[b];\n // Dummies keep less room between each other than real nodes do.\n const gap = va.node < 0 && vb.node < 0 ? nodeGap / 2 : nodeGap;\n return va.crossSize / 2 + gap + vb.crossSize / 2;\n };\n for (const layer of layers) {\n let at = 0;\n layer.forEach((v, i) => {\n if (i > 0) at += gapBetween(layer[i - 1], v);\n vertices[v].cross = at;\n });\n }\n // Pull toward the neighbours: down from the layer before, up from the layer\n // after, and once more from both sides. Dummies weigh more, so long edges run straight.\n const passes: Array<\"down\" | \"up\" | \"both\"> = [\"down\", \"up\", \"down\", \"up\", \"both\", \"both\"];\n for (const pass of passes) {\n const range = pass === \"up\" ? layers.map((_, l) => layers.length - 1 - l) : layers.map((_, l) => l);\n for (const l of range) {\n const layer = layers[l];\n if (layer.length === 0) continue;\n const desired = layer.map((v) => {\n const vertex = vertices[v];\n const neighbours =\n pass === \"down\" ? vertex.preds : pass === \"up\" ? vertex.succs : [...vertex.preds, ...vertex.succs];\n if (neighbours.length === 0) return vertex.cross;\n return neighbours.reduce((sum, n) => sum + vertices[n].cross, 0) / neighbours.length;\n });\n const gaps = layer.slice(1).map((v, i) => gapBetween(layer[i], v));\n const weights = layer.map((v) => (vertices[v].node < 0 ? 2 : 1));\n place(desired, gaps, weights).forEach((cross, i) => (vertices[layer[i]].cross = cross));\n }\n }\n}\n\n// ---- Steps 4, 7, 8: one connected part, then all of them ----\n\ninterface PartLayout {\n /** Real node index → its rectangle in part coordinates (rank, cross). */\n nodes: Map<number, { rank: number; cross: number; layer: number; order: number }>;\n /** Edge index → points in part coordinates (rank, cross). */\n edges: Map<number, Array<{ rank: number; cross: number }>>;\n rankExtent: number;\n crossExtent: number;\n}\n\nfunction layoutPart(\n members: number[],\n graph: Normalised,\n edgeList: number[],\n rankSizeOf: (n: number) => number,\n crossSizeOf: (n: number) => number,\n rankGap: number,\n nodeGap: number,\n sweeps: number\n): PartLayout {\n const local = new Map<number, number>();\n members.forEach((n, i) => local.set(n, i));\n const arcs: Array<[number, number]> = edgeList.map((e) => {\n const edge = graph.edges[e];\n const from = local.get(edge.from)!;\n const to = local.get(edge.to)!;\n return edge.reversed ? [to, from] : [from, to];\n });\n const layerOf = assignLayers(members.length, arcs);\n\n const vertices: Vertex[] = members.map((n, i) => ({\n node: n,\n rankSize: rankSizeOf(n),\n crossSize: crossSizeOf(n),\n layer: layerOf[i],\n cross: 0,\n preds: [],\n succs: [],\n }));\n const segments: Segment[] = edgeList.map((e, k) => {\n const [from, to] = arcs[k];\n const chain = [from];\n let previous = from;\n for (let l = vertices[from].layer + 1; l < vertices[to].layer; l++) {\n const dummy = vertices.length;\n vertices.push({ node: -1, rankSize: 0, crossSize: 0, layer: l, cross: 0, preds: [], succs: [] });\n vertices[previous].succs.push(dummy);\n vertices[dummy].preds.push(previous);\n chain.push(dummy);\n previous = dummy;\n }\n vertices[previous].succs.push(to);\n vertices[to].preds.push(previous);\n chain.push(to);\n return { edge: e, chain };\n });\n\n // Each layer starts in the order of first appearance in a walk from the\n // sources in input order; the sweeps take it from there.\n const layerCount = vertices.reduce((max, v) => Math.max(max, v.layer + 1), 0);\n const layers: number[][] = Array.from({ length: layerCount }, () => []);\n vertices.forEach((v, i) => layers[v.layer].push(i));\n orderLayers(layers, vertices, sweeps);\n assignCross(layers, vertices, nodeGap);\n\n // Layer bands along the rank axis: each as thick as its thickest node.\n const thickness = layers.map((layer) => layer.reduce((max, v) => Math.max(max, vertices[v].rankSize), 0));\n const start: number[] = [];\n let rank = 0;\n thickness.forEach((t, l) => {\n start[l] = rank;\n rank += t + (l + 1 < thickness.length ? rankGap : 0);\n });\n\n let minCross = Infinity;\n let maxCross = -Infinity;\n for (const v of vertices) {\n minCross = Math.min(minCross, v.cross - v.crossSize / 2);\n maxCross = Math.max(maxCross, v.cross + v.crossSize / 2);\n }\n const shift = Number.isFinite(minCross) ? -minCross : 0;\n\n const nodes: PartLayout[\"nodes\"] = new Map();\n layers.forEach((layer, l) =>\n layer.forEach((v, order) => {\n const vertex = vertices[v];\n if (vertex.node < 0) return;\n nodes.set(vertex.node, {\n rank: start[l] + (thickness[l] - vertex.rankSize) / 2,\n cross: vertex.cross - vertex.crossSize / 2 + shift,\n layer: l,\n order,\n });\n })\n );\n\n const edges: PartLayout[\"edges\"] = new Map();\n for (const { edge, chain } of segments) {\n const points: Array<{ rank: number; cross: number }> = [];\n chain.forEach((v, i) => {\n const vertex = vertices[v];\n const l = vertex.layer;\n const cross = vertex.cross + shift;\n const bandStart = start[l] + (thickness[l] - vertex.rankSize) / 2;\n if (i === 0) points.push({ rank: bandStart + vertex.rankSize, cross });\n else if (i === chain.length - 1) points.push({ rank: bandStart, cross });\n else {\n // Straight through the band of a layer it skips, so it never cuts a node.\n points.push({ rank: start[l], cross }, { rank: start[l] + thickness[l], cross });\n }\n });\n if (graph.edges[edge].reversed) points.reverse();\n edges.set(edge, points);\n }\n\n return {\n nodes,\n edges,\n rankExtent: rank,\n crossExtent: Number.isFinite(maxCross) ? maxCross - minCross : 0,\n };\n}\n\n/**\n * Lays out a directed graph in layers. Never throws: unknown ids, self-loops\n * and duplicates are dropped (and reported through `warn`), and the edges that\n * close a cycle are drawn against the layer direction, marked `reversed`.\n */\nexport function dagLayout(input: DagLayoutInput): DagLayoutResult {\n const direction = input.direction ?? \"LR\";\n const rankGap = input.rankGap ?? 64;\n const nodeGap = input.nodeGap ?? 24;\n const sweeps = input.sweeps ?? 8;\n const graph = normalise(input);\n const lr = direction === \"LR\";\n const rankSizeOf = (n: number): number => (lr ? graph.nodes[n].width : graph.nodes[n].height);\n const crossSizeOf = (n: number): number => (lr ? graph.nodes[n].height : graph.nodes[n].width);\n\n // Connected parts (edges taken both ways), in the order of their first node.\n const parent = graph.nodes.map((_, i) => i);\n const find = (v: number): number => {\n while (parent[v] !== v) {\n parent[v] = parent[parent[v]]!;\n v = parent[v]!;\n }\n return v;\n };\n for (const edge of graph.edges) {\n const a = find(edge.from);\n const b = find(edge.to);\n if (a !== b) parent[Math.max(a, b)] = Math.min(a, b);\n }\n const parts = new Map<number, { members: number[]; edges: number[] }>();\n graph.nodes.forEach((_, i) => {\n const root = find(i);\n if (!parts.has(root)) parts.set(root, { members: [], edges: [] });\n parts.get(root)!.members.push(i);\n });\n graph.edges.forEach((edge, e) => parts.get(find(edge.from))!.edges.push(e));\n\n const placedNodes = new Map<number, DagLayoutNode>();\n const placedEdges = new Map<number, DagPoint[]>();\n const toPoint = (rank: number, cross: number): DagPoint => (lr ? { x: rank, y: cross } : { x: cross, y: rank });\n let crossAt = 0;\n let rankExtent = 0;\n for (const part of parts.values()) {\n const laid = layoutPart(part.members, graph, part.edges, rankSizeOf, crossSizeOf, rankGap, nodeGap, sweeps);\n for (const [n, p] of laid.nodes) {\n const node = graph.nodes[n];\n placedNodes.set(n, {\n id: node.id,\n ...toPoint(p.rank, p.cross + crossAt),\n width: node.width,\n height: node.height,\n layer: p.layer,\n order: p.order,\n });\n }\n for (const [e, points] of laid.edges) {\n placedEdges.set(\n e,\n points.map((p) => toPoint(p.rank, p.cross + crossAt))\n );\n }\n rankExtent = Math.max(rankExtent, laid.rankExtent);\n crossAt += laid.crossExtent + nodeGap * 2;\n }\n const crossExtent = Math.max(0, crossAt - nodeGap * 2);\n\n const nodes = new Map<string, DagLayoutNode>();\n graph.nodes.forEach((node, i) => nodes.set(node.id, placedNodes.get(i)!));\n // A two-cycle (a->b and b->a) would draw both edges on one curve: the\n // turned-around one moves across, still ending on both nodes.\n const pairs = new Set(graph.edges.map((edge) => `${edge.from} ${edge.to}`));\n const edges = graph.edges.map((edge, e) => {\n let points = placedEdges.get(e)!;\n if (edge.reversed && pairs.has(`${edge.to} ${edge.from}`)) {\n const across = (n: number): number => (lr ? graph.nodes[n].height : graph.nodes[n].width);\n const offset = Math.min(8, across(edge.from) / 4, across(edge.to) / 4);\n points = points.map((p) => (lr ? { x: p.x, y: p.y + offset } : { x: p.x + offset, y: p.y }));\n }\n return { id: edge.id, source: edge.source, target: edge.target, points, reversed: edge.reversed };\n });\n const extent = toPoint(rankExtent, crossExtent);\n return { nodes, edges, width: extent.x, height: extent.y };\n}\n\n/**\n * An SVG path through an edge's points: a smooth S-curve between layers, a\n * straight line through the layers it skips.\n */\nexport function dagEdgePath(points: readonly DagPoint[], direction: DagDirection = \"LR\"): string {\n if (points.length === 0) return \"\";\n const round = (n: number): number => Math.round(n * 10) / 10;\n const first = points[0];\n let d = `M${round(first.x)},${round(first.y)}`;\n for (let i = 1; i < points.length; i++) {\n const a = points[i - 1];\n const b = points[i];\n if (direction === \"LR\") {\n const mid = (a.x + b.x) / 2;\n d += ` C${round(mid)},${round(a.y)} ${round(mid)},${round(b.y)} ${round(b.x)},${round(b.y)}`;\n } else {\n const mid = (a.y + b.y) / 2;\n d += ` C${round(a.x)},${round(mid)} ${round(b.x)},${round(mid)} ${round(b.x)},${round(b.y)}`;\n }\n }\n return d;\n}\n"],"names":["dagEdgeId","edge","_a","normalise","input","warn","nodes","index","node","edges","pairs","ids","from","to","missing","pair","id","out","i","state","root","stack","top","v","next","list","assignLayers","count","arcs","inDegree","u","hasPred","d","layer","order","queue","head","succs","s","crossingsBetween","upper","vertices","position","a","b","size","tree","crossings","j","totalCrossings","layers","sum","l","reorder","down","key","neighbours","n","orderLayers","sweeps","best","bestCrossings","stale","sweep","place","desired","gaps","weights","offset","blocks","block","last","weight","result","k","assignCross","nodeGap","gapBetween","va","vb","gap","at","passes","pass","range","_","vertex","cross","layoutPart","members","graph","edgeList","rankSizeOf","crossSizeOf","rankGap","local","e","layerOf","segments","chain","previous","dummy","layerCount","max","thickness","start","rank","t","minCross","maxCross","shift","points","bandStart","dagLayout","_b","_c","_d","direction","lr","parent","find","parts","placedNodes","placedEdges","toPoint","crossAt","rankExtent","part","laid","p","crossExtent","across","extent","dagEdgePath","round","first","mid"],"mappings":"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"}
|