diff --git a/packages/twenty-front-component-renderer/src/__stories__/html-tag/interactive/a/a-external-navigation.stories.tsx b/packages/twenty-front-component-renderer/src/__stories__/html-tag/interactive/a/a-external-navigation.stories.tsx deleted file mode 100644 index fc2377df42..0000000000 --- a/packages/twenty-front-component-renderer/src/__stories__/html-tag/interactive/a/a-external-navigation.stories.tsx +++ /dev/null @@ -1,54 +0,0 @@ -import { type Meta, type StoryObj } from '@storybook/react-vite'; -import { expect, fn, userEvent, waitFor, within } from 'storybook/test'; - -import { FrontComponentRenderer } from '@/host/components/FrontComponentRenderer'; -import { - FRONT_COMPONENT_STORY_DEFAULT_ARGS, - resetFrontComponentStoryMocks, -} from '@/__stories__/shared/test-utils/createFrontComponentStoryMeta'; -import { expectFrontComponentMounted } from '@/__stories__/shared/test-utils/matchers/expectFrontComponentMounted'; -import { runFrontComponentStory } from '@/__stories__/shared/test-utils/runFrontComponentStory'; -import { INTERACTION_TIMEOUT } from '@/__stories__/shared/test-utils/timeouts'; - -const requestExternalNavigation = fn(); - -const meta: Meta = { - title: 'FrontComponent/HtmlTag/Interactive/A/ExternalNavigation', - component: FrontComponentRenderer, - parameters: { layout: 'centered' }, - args: { - ...FRONT_COMPONENT_STORY_DEFAULT_ARGS, - onRequestExternalNavigation: requestExternalNavigation, - }, - beforeEach: () => { - resetFrontComponentStoryMocks(); - requestExternalNavigation.mockClear(); - }, -}; - -export default meta; - -type Story = StoryObj; - -export const ExternalAnchorClickIsHandedToTheHost: Story = - runFrontComponentStory({ - frontComponentBundleName: 'a-properties', - play: async ({ canvasElement }) => { - const canvas = within(canvasElement); - - await expectFrontComponentMounted(canvas); - - const link = await canvas.findByTestId('subject'); - - await userEvent.click(link); - - await waitFor( - () => { - expect(requestExternalNavigation).toHaveBeenCalledWith( - expect.objectContaining({ url: 'https://example.com/probe' }), - ); - }, - { timeout: INTERACTION_TIMEOUT }, - ); - }, - }); diff --git a/packages/twenty-front-component-renderer/src/host/components/FrontComponentRenderer.tsx b/packages/twenty-front-component-renderer/src/host/components/FrontComponentRenderer.tsx index ba128fbe86..5124f325a5 100644 --- a/packages/twenty-front-component-renderer/src/host/components/FrontComponentRenderer.tsx +++ b/packages/twenty-front-component-renderer/src/host/components/FrontComponentRenderer.tsx @@ -1,7 +1,5 @@ import { ROOT_CONTAINER_STYLE } from '@/host/constants/RootContainerStyle'; -import { FrontComponentExternalNavigationContext } from '@/host/contexts/FrontComponentExternalNavigationContext'; import { FrontComponentGeometryTrackerContext } from '@/host/contexts/FrontComponentGeometryTrackerContext'; -import { type RequestExternalNavigation } from '@/host/types/RequestExternalNavigation'; import { createGeometryTracker } from '@/host/utils/createGeometryTracker'; import { FrontComponentConfirmationModalResultEffect } from '@/remote/components/FrontComponentConfirmationModalResultEffect'; import { FrontComponentErrorEffect } from '@/remote/components/FrontComponentErrorEffect'; @@ -39,7 +37,6 @@ type FrontComponentRendererProps = { applicationVariables?: Record; executionContext: FrontComponentExecutionContext; frontComponentHostCommunicationApi: FrontComponentHostCommunicationApi; - onRequestExternalNavigation?: RequestExternalNavigation; onError: (error?: Error) => void; colorScheme: 'light' | 'dark'; loadingFallback?: ReactNode; @@ -54,7 +51,6 @@ export const FrontComponentRenderer = ({ applicationVariables, executionContext, frontComponentHostCommunicationApi, - onRequestExternalNavigation, onError, colorScheme, loadingFallback, @@ -131,14 +127,10 @@ export const FrontComponentRenderer = ({ resetKeys={[componentUrl]} fallbackRender={() => null} > - - - + )} diff --git a/packages/twenty-front-component-renderer/src/host/contexts/FrontComponentExternalNavigationContext.ts b/packages/twenty-front-component-renderer/src/host/contexts/FrontComponentExternalNavigationContext.ts deleted file mode 100644 index 42ac7fc296..0000000000 --- a/packages/twenty-front-component-renderer/src/host/contexts/FrontComponentExternalNavigationContext.ts +++ /dev/null @@ -1,6 +0,0 @@ -import { createContext } from 'react'; - -import { type RequestExternalNavigation } from '@/host/types/RequestExternalNavigation'; - -export const FrontComponentExternalNavigationContext = - createContext(null); diff --git a/packages/twenty-front-component-renderer/src/host/hooks/useHtmlHostElementProps.ts b/packages/twenty-front-component-renderer/src/host/hooks/useHtmlHostElementProps.ts index b262aa1f57..b4b85b8b4e 100644 --- a/packages/twenty-front-component-renderer/src/host/hooks/useHtmlHostElementProps.ts +++ b/packages/twenty-front-component-renderer/src/host/hooks/useHtmlHostElementProps.ts @@ -1,6 +1,5 @@ import { useContext } from 'react'; -import { FrontComponentExternalNavigationContext } from '@/host/contexts/FrontComponentExternalNavigationContext'; import { FrontComponentInputFocusContext, type SetEditableFocused, @@ -10,7 +9,6 @@ import { useGeometryNodeRef } from '@/host/hooks/useGeometryNodeRef'; import { useReactUnsupportedEventListenerRef } from '@/host/hooks/useReactUnsupportedEventListenerRef'; import { type ElementRefCallback } from '@/host/types/ElementRefCallback'; import { buildHostReactPropsFromRemoteProps } from '@/host/utils/buildHostReactPropsFromRemoteProps'; -import { createAnchorNavigationClickHandler } from '@/host/utils/createAnchorNavigationClickHandler'; import { createDropTargetGuardProps } from '@/host/utils/createDropTargetGuardProps'; import { extractReactUnsupportedEventHandlers } from '@/host/utils/extractReactUnsupportedEventHandlers'; import { getRemoteElementIdFromProps } from '@/host/utils/getRemoteElementIdFromProps'; @@ -29,9 +27,6 @@ export const useHtmlHostElementProps = ( htmlTag: string, ): HtmlHostElementProps => { const setEditableFocused = useContext(FrontComponentInputFocusContext); - const requestExternalNavigation = useContext( - FrontComponentExternalNavigationContext, - ); const remoteElementId = getRemoteElementIdFromProps(props); @@ -51,14 +46,6 @@ export const useHtmlHostElementProps = ( geometryNodeRef, ]); - const anchorNavigationClickHandler = - htmlTag === 'a' && - createAnchorNavigationClickHandler({ - href: reactBindableProps.href, - remoteOnClick: reactBindableProps.onClick, - requestExternalNavigation, - }); - const hostEnforcedProps: Record = { ...createDropTargetGuardProps(reactBindableProps), ...(htmlTag === 'iframe' && { @@ -68,10 +55,6 @@ export const useHtmlHostElementProps = ( ...(htmlTag === 'form' && { onSubmit: preventDefaultThenForwardToRemote(reactBindableProps.onSubmit), }), - ...(anchorNavigationClickHandler && { - onClick: anchorNavigationClickHandler, - onAuxClick: anchorNavigationClickHandler, - }), }; return { diff --git a/packages/twenty-front-component-renderer/src/host/types/RequestExternalNavigation.ts b/packages/twenty-front-component-renderer/src/host/types/RequestExternalNavigation.ts deleted file mode 100644 index cd226048d3..0000000000 --- a/packages/twenty-front-component-renderer/src/host/types/RequestExternalNavigation.ts +++ /dev/null @@ -1 +0,0 @@ -export type RequestExternalNavigation = (request: { url: string }) => void; diff --git a/packages/twenty-front-component-renderer/src/host/utils/__tests__/createAnchorNavigationClickHandler.test.ts b/packages/twenty-front-component-renderer/src/host/utils/__tests__/createAnchorNavigationClickHandler.test.ts deleted file mode 100644 index d0980081c0..0000000000 --- a/packages/twenty-front-component-renderer/src/host/utils/__tests__/createAnchorNavigationClickHandler.test.ts +++ /dev/null @@ -1,150 +0,0 @@ -import { type MouseEvent } from 'react'; - -import { createAnchorNavigationClickHandler } from '../createAnchorNavigationClickHandler'; - -const createMouseEvent = ( - button: number, - modifierKeys: { - metaKey?: boolean; - ctrlKey?: boolean; - shiftKey?: boolean; - } = {}, -) => { - const preventDefault = jest.fn(); - - return { - event: { - button, - preventDefault, - metaKey: modifierKeys.metaKey ?? false, - ctrlKey: modifierKeys.ctrlKey ?? false, - shiftKey: modifierKeys.shiftKey ?? false, - } as unknown as MouseEvent, - preventDefault, - }; -}; - -describe('createAnchorNavigationClickHandler', () => { - it('should intercept an external primary click without forwarding to the remote handler', () => { - const requestExternalNavigation = jest.fn(); - const remoteOnClick = jest.fn(); - const { event, preventDefault } = createMouseEvent(0); - - createAnchorNavigationClickHandler({ - href: 'https://example.com/probe', - remoteOnClick, - requestExternalNavigation, - })(event); - - expect(preventDefault).toHaveBeenCalledTimes(1); - expect(requestExternalNavigation).toHaveBeenCalledWith({ - url: 'https://example.com/probe', - }); - expect(remoteOnClick).not.toHaveBeenCalled(); - }); - - it('should ignore the anchor target so the host always decides how to open the url', () => { - const requestExternalNavigation = jest.fn(); - const { event } = createMouseEvent(0); - - createAnchorNavigationClickHandler({ - href: 'https://example.com/probe', - remoteOnClick: undefined, - requestExternalNavigation, - })(event); - - expect(requestExternalNavigation).toHaveBeenCalledWith({ - url: 'https://example.com/probe', - }); - }); - - it('should not intercept a same-origin click but still forward it', () => { - const requestExternalNavigation = jest.fn(); - const remoteOnClick = jest.fn(); - const { event, preventDefault } = createMouseEvent(0); - - createAnchorNavigationClickHandler({ - href: 'http://localhost/objects/people', - remoteOnClick, - requestExternalNavigation, - })(event); - - expect(preventDefault).not.toHaveBeenCalled(); - expect(requestExternalNavigation).not.toHaveBeenCalled(); - expect(remoteOnClick).toHaveBeenCalledWith(event); - }); - - it('should not prevent default when no navigation handler is provided', () => { - const remoteOnClick = jest.fn(); - const { event, preventDefault } = createMouseEvent(0); - - createAnchorNavigationClickHandler({ - href: 'https://example.com/probe', - remoteOnClick, - requestExternalNavigation: null, - })(event); - - expect(preventDefault).not.toHaveBeenCalled(); - expect(remoteOnClick).toHaveBeenCalledWith(event); - }); - - it('should intercept an external middle click without forwarding to the remote handler', () => { - const requestExternalNavigation = jest.fn(); - const remoteOnClick = jest.fn(); - const { event, preventDefault } = createMouseEvent(1); - - createAnchorNavigationClickHandler({ - href: 'https://example.com/probe', - remoteOnClick, - requestExternalNavigation, - })(event); - - expect(preventDefault).toHaveBeenCalledTimes(1); - expect(requestExternalNavigation).toHaveBeenCalledWith({ - url: 'https://example.com/probe', - }); - expect(remoteOnClick).not.toHaveBeenCalled(); - }); - - it.each([ - ['a cmd (meta) modifier', { metaKey: true }], - ['a ctrl modifier', { ctrlKey: true }], - ['a shift modifier', { shiftKey: true }], - ] as Array< - [string, { metaKey?: boolean; ctrlKey?: boolean; shiftKey?: boolean }] - >)( - 'should intercept a primary click with %s without forwarding to the remote handler', - (_label, modifierKeys) => { - const requestExternalNavigation = jest.fn(); - const remoteOnClick = jest.fn(); - const { event } = createMouseEvent(0, modifierKeys); - - createAnchorNavigationClickHandler({ - href: 'https://example.com/probe', - remoteOnClick, - requestExternalNavigation, - })(event); - - expect(requestExternalNavigation).toHaveBeenCalledWith({ - url: 'https://example.com/probe', - }); - expect(remoteOnClick).not.toHaveBeenCalled(); - }, - ); - - it('should ignore a right click', () => { - const requestExternalNavigation = jest.fn(); - const remoteOnClick = jest.fn(); - const { event, preventDefault } = createMouseEvent(2); - - createAnchorNavigationClickHandler({ - href: 'https://example.com/probe', - remoteOnClick, - requestExternalNavigation, - })(event); - - expect(preventDefault).not.toHaveBeenCalled(); - expect(requestExternalNavigation).not.toHaveBeenCalled(); - expect(remoteOnClick).not.toHaveBeenCalled(); - }); -}); diff --git a/packages/twenty-front-component-renderer/src/host/utils/__tests__/createHtmlHostWrapper.test.ts b/packages/twenty-front-component-renderer/src/host/utils/__tests__/createHtmlHostWrapper.test.ts index d6ac4a79f5..14a1deddfb 100644 --- a/packages/twenty-front-component-renderer/src/host/utils/__tests__/createHtmlHostWrapper.test.ts +++ b/packages/twenty-front-component-renderer/src/host/utils/__tests__/createHtmlHostWrapper.test.ts @@ -6,8 +6,6 @@ import { createRoot, type Root } from 'react-dom/client'; import { renderToStaticMarkup } from 'react-dom/server'; import { jsx } from 'react/jsx-runtime'; -import { FrontComponentExternalNavigationContext } from '@/host/contexts/FrontComponentExternalNavigationContext'; - import { createHtmlHostWrapper } from '../createHtmlHostWrapper'; ( @@ -337,86 +335,3 @@ describe('createHtmlHostWrapper client events', () => { ); }); }); - -describe('createHtmlHostWrapper anchor navigation', () => { - let container: HTMLDivElement; - let root: Root; - - beforeEach(() => { - container = document.createElement('div'); - document.body.appendChild(container); - root = createRoot(container); - }); - - afterEach(() => { - act(() => { - root.unmount(); - }); - container.remove(); - }); - - const renderAnchor = ( - props: Record, - requestExternalNavigation: ((request: unknown) => void) | null, - ) => { - const Wrapper = createHtmlHostWrapper('a'); - - act(() => { - root.render( - createElement( - FrontComponentExternalNavigationContext.Provider, - { value: requestExternalNavigation }, - createElement(Wrapper, props, 'link'), - ), - ); - }); - - return container.querySelector('a') as HTMLAnchorElement; - }; - - const clickAnchor = (anchor: HTMLAnchorElement): MouseEvent => { - const clickEvent = new MouseEvent('click', { - bubbles: true, - cancelable: true, - button: 0, - }); - - act(() => { - anchor.dispatchEvent(clickEvent); - }); - - return clickEvent; - }; - - it('should prevent default and request navigation for an external anchor click', () => { - const requestExternalNavigation = jest.fn(); - const remoteOnClick = jest.fn(); - - const anchor = renderAnchor( - { href: 'https://example.com/probe', onClick: remoteOnClick }, - requestExternalNavigation, - ); - - const clickEvent = clickAnchor(anchor); - - expect(clickEvent.defaultPrevented).toBe(true); - expect(requestExternalNavigation).toHaveBeenCalledWith({ - url: 'https://example.com/probe', - }); - expect(remoteOnClick).not.toHaveBeenCalled(); - }); - - it('should not request navigation for a same-origin anchor click', () => { - const requestExternalNavigation = jest.fn(); - - const anchor = renderAnchor( - { href: 'http://localhost/objects/people' }, - requestExternalNavigation, - ); - - const clickEvent = clickAnchor(anchor); - - expect(clickEvent.defaultPrevented).toBe(false); - expect(requestExternalNavigation).not.toHaveBeenCalled(); - }); -}); diff --git a/packages/twenty-front-component-renderer/src/host/utils/__tests__/isExternalNavigationUrl.test.ts b/packages/twenty-front-component-renderer/src/host/utils/__tests__/isExternalNavigationUrl.test.ts deleted file mode 100644 index b2f5a324c0..0000000000 --- a/packages/twenty-front-component-renderer/src/host/utils/__tests__/isExternalNavigationUrl.test.ts +++ /dev/null @@ -1,35 +0,0 @@ -import { isExternalNavigationUrl } from '../isExternalNavigationUrl'; - -describe('isExternalNavigationUrl (jest jsdom test page origin is http://localhost)', () => { - it('should return true for a cross-origin https url', () => { - expect(isExternalNavigationUrl('https://example.com/probe')).toBe(true); - }); - - it('should return true for a cross-origin http url', () => { - expect(isExternalNavigationUrl('http://example.com')).toBe(true); - }); - - it('should return false for a same-origin absolute url', () => { - expect(isExternalNavigationUrl('http://localhost/settings')).toBe(false); - }); - - it('should return false for a relative path', () => { - expect(isExternalNavigationUrl('/objects/people')).toBe(false); - }); - - it('should return false for a mailto url', () => { - expect(isExternalNavigationUrl('mailto:hello@example.com')).toBe(false); - }); - - it('should return false for a tel url', () => { - expect(isExternalNavigationUrl('tel:+15551234567')).toBe(false); - }); - - it('should return false for a javascript url', () => { - expect(isExternalNavigationUrl('javascript:alert(1)')).toBe(false); - }); - - it('should return false for an empty href', () => { - expect(isExternalNavigationUrl('')).toBe(false); - }); -}); diff --git a/packages/twenty-front-component-renderer/src/host/utils/createAnchorNavigationClickHandler.ts b/packages/twenty-front-component-renderer/src/host/utils/createAnchorNavigationClickHandler.ts deleted file mode 100644 index a61d37df30..0000000000 --- a/packages/twenty-front-component-renderer/src/host/utils/createAnchorNavigationClickHandler.ts +++ /dev/null @@ -1,52 +0,0 @@ -import { isFunction, isNonEmptyString } from '@sniptt/guards'; -import { type MouseEvent } from 'react'; -import { isDefined } from 'twenty-shared/utils'; - -import { type RemoteEventHandler } from '@/host/types/RemoteEventHandler'; -import { type RequestExternalNavigation } from '@/host/types/RequestExternalNavigation'; -import { isExternalNavigationUrl } from '@/host/utils/isExternalNavigationUrl'; - -const PRIMARY_MOUSE_BUTTON = 0; -const MIDDLE_MOUSE_BUTTON = 1; - -type CreateAnchorNavigationClickHandlerParams = { - href: unknown; - remoteOnClick: unknown; - requestExternalNavigation: RequestExternalNavigation | null; -}; - -export const createAnchorNavigationClickHandler = - ({ - href, - remoteOnClick, - requestExternalNavigation, - }: CreateAnchorNavigationClickHandlerParams) => - (event: MouseEvent) => { - // Bound to both onClick and onAuxClick: a middle click opens a new tab - // through auxclick, never click. auxclick also fires on right click, which - // must stay untouched so the native context menu keeps working. - const clickCanOpenNavigation = - event.button === PRIMARY_MOUSE_BUTTON || - event.button === MIDDLE_MOUSE_BUTTON; - - if ( - isDefined(requestExternalNavigation) && - clickCanOpenNavigation && - isNonEmptyString(href) && - isExternalNavigationUrl(href) - ) { - event.preventDefault(); - - requestExternalNavigation({ - url: new URL(href, window.location.href).href, - }); - - return; - } - - const clickIsPrimaryActivation = event.button === PRIMARY_MOUSE_BUTTON; - - if (clickIsPrimaryActivation && isFunction(remoteOnClick)) { - (remoteOnClick as RemoteEventHandler)(event); - } - }; diff --git a/packages/twenty-front-component-renderer/src/host/utils/isExternalNavigationUrl.ts b/packages/twenty-front-component-renderer/src/host/utils/isExternalNavigationUrl.ts deleted file mode 100644 index 7128f76ce3..0000000000 --- a/packages/twenty-front-component-renderer/src/host/utils/isExternalNavigationUrl.ts +++ /dev/null @@ -1,13 +0,0 @@ -export const isExternalNavigationUrl = (href: string): boolean => { - try { - const resolvedUrl = new URL(href, window.location.href); - - if (resolvedUrl.protocol !== 'http:' && resolvedUrl.protocol !== 'https:') { - return false; - } - - return resolvedUrl.origin !== window.location.origin; - } catch { - return false; - } -}; diff --git a/packages/twenty-front-component-renderer/src/index.ts b/packages/twenty-front-component-renderer/src/index.ts index ca3463fda9..43f31bd35f 100644 --- a/packages/twenty-front-component-renderer/src/index.ts +++ b/packages/twenty-front-component-renderer/src/index.ts @@ -1,10 +1,8 @@ export { FrontComponentRenderer } from './host/components/FrontComponentRenderer'; -export { FrontComponentExternalNavigationContext } from './host/contexts/FrontComponentExternalNavigationContext'; export { FrontComponentInputFocusContext, type SetEditableFocused, } from './host/contexts/FrontComponentInputFocusContext'; -export { type RequestExternalNavigation } from './host/types/RequestExternalNavigation'; export { componentRegistry } from './host/generated/host-component-registry'; export { FrontComponentConfirmationModalResultEffect } from './remote/components/FrontComponentConfirmationModalResultEffect'; export { FrontComponentErrorEffect } from './remote/components/FrontComponentErrorEffect'; diff --git a/packages/twenty-front/src/modules/app/components/WorkspaceAppProviders.tsx b/packages/twenty-front/src/modules/app/components/WorkspaceAppProviders.tsx index ae1e71e7fb..8af6f3478f 100644 --- a/packages/twenty-front/src/modules/app/components/WorkspaceAppProviders.tsx +++ b/packages/twenty-front/src/modules/app/components/WorkspaceAppProviders.tsx @@ -16,7 +16,6 @@ import { CommandRunner } from '@/command-menu-item/engine-command/components/Com import { MainContextStoreProvider } from '@/context-store/components/MainContextStoreProvider'; import { ErrorMessageEffect } from '@/error-handler/components/ErrorMessageEffect'; import { PromiseRejectionEffect } from '@/error-handler/components/PromiseRejectionEffect'; -import { FrontComponentExternalLinkModalManager } from '@/front-components/components/FrontComponentExternalLinkModalManager'; import { IsMinimalMetadataReadyEffect } from '@/metadata-store/effect-components/IsMinimalMetadataReadyEffect'; import { MinimalMetadataLoadEffect } from '@/metadata-store/effect-components/MinimalMetadataLoadEffect'; import { UserMetadataProviderInitialEffect } from '@/metadata-store/effect-components/UserMetadataProviderInitialEffect'; @@ -71,7 +70,6 @@ export const WorkspaceAppProviders = () => { - diff --git a/packages/twenty-front/src/modules/front-components/components/FrontComponentExternalLinkModal.tsx b/packages/twenty-front/src/modules/front-components/components/FrontComponentExternalLinkModal.tsx deleted file mode 100644 index 5aa826f579..0000000000 --- a/packages/twenty-front/src/modules/front-components/components/FrontComponentExternalLinkModal.tsx +++ /dev/null @@ -1,153 +0,0 @@ -import { styled } from '@linaria/react'; -import { t } from '@lingui/core/macro'; -import { useId } from 'react'; -import { Button, Checkbox } from 'twenty-ui/input'; -import { themeCssVariables } from 'twenty-ui/theme-constants'; -import { H1Title, H1TitleFontColor } from 'twenty-ui/typography'; - -import { FRONT_COMPONENT_EXTERNAL_LINK_MODAL_ID } from '@/front-components/constants/FrontComponentExternalLinkModalId'; -import { getExternalLinkDisplayUrl } from '@/front-components/utils/getExternalLinkDisplayUrl'; -import { ModalStatefulWrapper } from '@/ui/layout/modal/components/ModalStatefulWrapper'; -import { useModal } from '@/ui/layout/modal/hooks/useModal'; - -const FRONT_COMPONENT_EXTERNAL_LINK_MODAL_WIDTH = 320; - -const StyledCenteredTitle = styled.div` - text-align: center; - - h2 { - margin-bottom: 0; - } -`; - -const StyledDestinationUrl = styled.span` - align-items: center; - align-self: center; - background-color: ${themeCssVariables.background.transparent.lighter}; - border: 1px solid ${themeCssVariables.border.color.strong}; - border-radius: ${themeCssVariables.border.radius.pill}; - color: ${themeCssVariables.font.color.primary}; - corner-shape: round; - display: inline-flex; - font-size: ${themeCssVariables.font.size.md}; - height: 20px; - justify-content: center; - max-width: 100%; - overflow: hidden; - padding: 0 ${themeCssVariables.spacing[2]}; -`; - -const StyledDestinationUrlText = styled.span` - min-width: 0; - overflow: hidden; - text-overflow: ellipsis; - white-space: nowrap; -`; - -const StyledActions = styled.div` - display: flex; - flex-direction: column; - gap: ${themeCssVariables.spacing[2]}; -`; - -const StyledTrustOriginRow = styled.div` - align-items: center; - display: flex; - gap: ${themeCssVariables.spacing[1]}; - justify-content: center; -`; - -const StyledTrustOriginLabel = styled.span` - color: ${themeCssVariables.font.color.primary}; - cursor: pointer; - font-size: ${themeCssVariables.font.size.sm}; -`; - -type FrontComponentExternalLinkModalProps = { - url: string; - shouldTrustOrigin: boolean; - onShouldTrustOriginChange: (shouldTrustOrigin: boolean) => void; - onConfirm: () => void; - onClose: () => void; -}; - -export const FrontComponentExternalLinkModal = ({ - url, - shouldTrustOrigin, - onShouldTrustOriginChange, - onConfirm, - onClose, -}: FrontComponentExternalLinkModalProps) => { - const { closeModal } = useModal(); - const trustOriginLabelId = useId(); - - const handleConfirmClick = () => { - closeModal(FRONT_COMPONENT_EXTERNAL_LINK_MODAL_ID); - onConfirm(); - }; - - const handleCancelClick = () => { - closeModal(FRONT_COMPONENT_EXTERNAL_LINK_MODAL_ID); - onClose(); - }; - - return ( - - - - - - - {getExternalLinkDisplayUrl(url)} - - - - - - onShouldTrustOriginChange(!shouldTrustOrigin)} - > - {t`Always allow links to this domain`} - - -