@chayns-components/core 5.5.23 → 5.5.25
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/AGENTS.md +44 -0
- package/LICENSE +21 -0
- package/lib/cjs/components/copyable-content/CopyableContent.js +12 -2
- package/lib/cjs/components/copyable-content/CopyableContent.js.map +1 -1
- package/lib/cjs/components/copyable-content/CopyableContent.styles.js +15 -8
- package/lib/cjs/components/copyable-content/CopyableContent.styles.js.map +1 -1
- package/lib/cjs/components/copyable-content/CopyableContent.test.js +43 -0
- package/lib/cjs/components/copyable-content/CopyableContent.test.js.map +1 -1
- package/lib/cjs/components/truncation/Truncation.js +61 -149
- package/lib/cjs/components/truncation/Truncation.js.map +1 -1
- package/lib/cjs/components/truncation/Truncation.styles.js +3 -4
- package/lib/cjs/components/truncation/Truncation.styles.js.map +1 -1
- package/lib/cjs/components/truncation/Truncation.test.js +61 -0
- package/lib/cjs/components/truncation/Truncation.test.js.map +1 -0
- package/lib/esm/components/copyable-content/CopyableContent.js +13 -3
- package/lib/esm/components/copyable-content/CopyableContent.js.map +1 -1
- package/lib/esm/components/copyable-content/CopyableContent.styles.js +14 -7
- package/lib/esm/components/copyable-content/CopyableContent.styles.js.map +1 -1
- package/lib/esm/components/copyable-content/CopyableContent.test.js +43 -0
- package/lib/esm/components/copyable-content/CopyableContent.test.js.map +1 -1
- package/lib/esm/components/truncation/Truncation.js +61 -149
- package/lib/esm/components/truncation/Truncation.js.map +1 -1
- package/lib/esm/components/truncation/Truncation.styles.js +2 -3
- package/lib/esm/components/truncation/Truncation.styles.js.map +1 -1
- package/lib/esm/components/truncation/Truncation.test.js +58 -0
- package/lib/esm/components/truncation/Truncation.test.js.map +1 -0
- package/lib/types/components/copyable-content/CopyableContent.d.ts +4 -0
- package/lib/types/components/copyable-content/CopyableContent.styles.d.ts +7 -2
- package/lib/types/components/truncation/Truncation.d.ts +1 -1
- package/lib/types/components/truncation/Truncation.styles.d.ts +1 -1
- package/package.json +5 -4
- package/lib/cjs/utils/truncation.js +0 -42
- package/lib/cjs/utils/truncation.js.map +0 -1
- package/lib/esm/utils/truncation.js +0 -35
- package/lib/esm/utils/truncation.js.map +0 -1
- package/lib/types/utils/truncation.d.ts +0 -1
|
@@ -15,7 +15,7 @@ export const StyledCopyableContent = styled.section`
|
|
|
15
15
|
--copyable-content-action-size: 32px;
|
|
16
16
|
--copyable-content-action-inset: 8px;
|
|
17
17
|
|
|
18
|
-
margin:
|
|
18
|
+
margin: 4px 0;
|
|
19
19
|
min-width: 0;
|
|
20
20
|
max-width: 100%;
|
|
21
21
|
overflow-x: clip;
|
|
@@ -23,13 +23,12 @@ export const StyledCopyableContent = styled.section`
|
|
|
23
23
|
padding-top: calc(
|
|
24
24
|
var(--copyable-content-action-size) + var(--copyable-content-action-inset) * 2
|
|
25
25
|
);
|
|
26
|
-
border-radius:
|
|
27
|
-
theme
|
|
28
|
-
}) => theme.cardBorderRadius}px;
|
|
26
|
+
border-radius: 8px;
|
|
29
27
|
background-color: ${getBackgroundColor};
|
|
30
28
|
color: ${({
|
|
31
29
|
theme
|
|
32
30
|
}) => theme.text};
|
|
31
|
+
box-shadow: 0 2px 8px rgba(0, 0, 0, 0.16);
|
|
33
32
|
`;
|
|
34
33
|
export const StyledCopyableContentActions = styled.div`
|
|
35
34
|
position: sticky;
|
|
@@ -68,7 +67,7 @@ export const StyledCopyableContentButton = styled.button`
|
|
|
68
67
|
}) => theme.text};
|
|
69
68
|
box-shadow: ${({
|
|
70
69
|
$isSticky
|
|
71
|
-
}) => $isSticky ? '0 2px 8px rgba(0, 0, 0, 0.
|
|
70
|
+
}) => $isSticky ? '0 2px 8px rgba(0, 0, 0, 0.28)' : 'none'};
|
|
72
71
|
transition:
|
|
73
72
|
background-color 0.15s ease,
|
|
74
73
|
border-color 0.15s ease,
|
|
@@ -76,6 +75,9 @@ export const StyledCopyableContentButton = styled.button`
|
|
|
76
75
|
transform 0.15s ease;
|
|
77
76
|
|
|
78
77
|
&:hover {
|
|
78
|
+
border-color: rgba(${({
|
|
79
|
+
theme
|
|
80
|
+
}) => theme['text-rgb']}, 0.18);
|
|
79
81
|
background-color: rgba(${({
|
|
80
82
|
theme
|
|
81
83
|
}) => theme['text-rgb']}, 0.1);
|
|
@@ -85,7 +87,7 @@ export const StyledCopyableContentButton = styled.button`
|
|
|
85
87
|
}
|
|
86
88
|
|
|
87
89
|
&:active {
|
|
88
|
-
transform: scale(0.
|
|
90
|
+
transform: scale(0.94);
|
|
89
91
|
}
|
|
90
92
|
|
|
91
93
|
&:focus-visible {
|
|
@@ -95,11 +97,16 @@ export const StyledCopyableContentButton = styled.button`
|
|
|
95
97
|
outline-offset: 2px;
|
|
96
98
|
}
|
|
97
99
|
`;
|
|
100
|
+
export const StyledCopyableContentTruncation = styled.div`
|
|
101
|
+
padding: 0 12px 12px;
|
|
102
|
+
`;
|
|
98
103
|
export const StyledCopyableContentBody = styled.div`
|
|
99
104
|
min-width: 0;
|
|
100
105
|
max-width: 100%;
|
|
101
106
|
overflow-wrap: anywhere;
|
|
102
|
-
padding:
|
|
107
|
+
padding: ${({
|
|
108
|
+
$shouldShowPadding = true
|
|
109
|
+
}) => $shouldShowPadding ? '0 12px 12px' : '0'};
|
|
103
110
|
|
|
104
111
|
h1,
|
|
105
112
|
h2,
|
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"CopyableContent.styles.js","names":["styled","CopyableContentAppearance","getBackgroundColor","$appearance","theme","Chat","secondaryColor","opacity","cardBackgroundOpacity","StyledCopyableContent","section","
|
|
1
|
+
{"version":3,"file":"CopyableContent.styles.js","names":["styled","CopyableContentAppearance","getBackgroundColor","$appearance","theme","Chat","secondaryColor","opacity","cardBackgroundOpacity","StyledCopyableContent","section","text","StyledCopyableContentActions","div","StyledCopyableContentActionGroup","StyledCopyableContentButton","button","$isSticky","buttonBackgroundColor","StyledCopyableContentTruncation","StyledCopyableContentBody","$shouldShowPadding","headline","primary"],"sources":["../../../../src/components/copyable-content/CopyableContent.styles.ts"],"sourcesContent":["import type { WithTheme } from '../color-scheme-provider/ColorSchemeProvider';\nimport styled from 'styled-components';\nimport { CopyableContentAppearance } from './CopyableContent.types';\n\ntype StyledCopyableContentProps = WithTheme<{\n $appearance: CopyableContentAppearance;\n}>;\n\nconst getBackgroundColor = ({ $appearance, theme }: StyledCopyableContentProps) => {\n if ($appearance === CopyableContentAppearance.Chat) {\n return 'rgba(0, 0, 0, 0.12)';\n }\n\n const secondaryColor = theme['secondary-100-rgb'] ?? '255, 255, 255';\n const opacity = theme.cardBackgroundOpacity ?? 1;\n\n return `rgba(${secondaryColor}, ${opacity})`;\n};\n\nexport const StyledCopyableContent = styled.section<StyledCopyableContentProps>`\n --copyable-content-action-size: 32px;\n --copyable-content-action-inset: 8px;\n\n margin: 4px 0;\n min-width: 0;\n max-width: 100%;\n overflow-x: clip;\n overflow-wrap: anywhere;\n padding-top: calc(\n var(--copyable-content-action-size) + var(--copyable-content-action-inset) * 2\n );\n border-radius: 8px;\n background-color: ${getBackgroundColor};\n color: ${({ theme }) => theme.text};\n box-shadow: 0 2px 8px rgba(0, 0, 0, 0.16);\n`;\n\ntype StyledCopyableContentButtonProps = WithTheme<{\n $isSticky: boolean;\n}>;\n\nexport const StyledCopyableContentActions = styled.div`\n position: sticky;\n top: var(--copyable-content-action-inset);\n z-index: 1;\n display: flex;\n justify-content: flex-end;\n height: calc(var(--copyable-content-action-size) + var(--copyable-content-action-inset));\n margin-top: calc(\n (var(--copyable-content-action-size) + var(--copyable-content-action-inset)) * -1\n );\n padding-right: var(--copyable-content-action-inset);\n`;\n\nexport const StyledCopyableContentActionGroup = styled.div`\n display: flex;\n gap: 4px;\n height: var(--copyable-content-action-size);\n`;\n\nexport const StyledCopyableContentButton = styled.button<StyledCopyableContentButtonProps>`\n box-sizing: border-box;\n border: 1px solid ${({ $isSticky, theme }) => ($isSticky ? theme['202'] : 'transparent')};\n border-radius: 4px;\n width: var(--copyable-content-action-size);\n height: var(--copyable-content-action-size);\n padding: 0;\n cursor: pointer;\n background-color: ${({ $isSticky, theme }) => ($isSticky ? theme['100'] : 'transparent')};\n color: ${({ theme }) => theme.text};\n box-shadow: ${({ $isSticky }) => ($isSticky ? '0 2px 8px rgba(0, 0, 0, 0.28)' : 'none')};\n transition:\n background-color 0.15s ease,\n border-color 0.15s ease,\n box-shadow 0.15s ease,\n transform 0.15s ease;\n\n &:hover {\n border-color: rgba(${({ theme }) => theme['text-rgb']}, 0.18);\n background-color: rgba(${({ theme }) => theme['text-rgb']}, 0.1);\n box-shadow: inset 0 0 0 1px rgba(${({ theme }) => theme['text-rgb']}, 0.06);\n }\n\n &:active {\n transform: scale(0.94);\n }\n\n &:focus-visible {\n outline: 2px solid ${({ theme }) => theme.buttonBackgroundColor};\n outline-offset: 2px;\n }\n`;\n\nexport const StyledCopyableContentTruncation = styled.div`\n padding: 0 12px 12px;\n`;\n\ntype StyledCopyableContentBodyProps = WithTheme<{\n $shouldShowPadding?: boolean;\n}>;\n\nexport const StyledCopyableContentBody = styled.div<StyledCopyableContentBodyProps>`\n min-width: 0;\n max-width: 100%;\n overflow-wrap: anywhere;\n padding: ${({ $shouldShowPadding = true }) => ($shouldShowPadding ? '0 12px 12px' : '0')};\n\n h1,\n h2,\n h3,\n h4,\n h5,\n h6,\n p,\n ul,\n ol,\n blockquote {\n margin: 0 0 12px;\n }\n\n h1,\n h2,\n h3,\n h4,\n h5,\n h6 {\n color: ${({ theme }) => theme.headline};\n }\n\n ul,\n ol {\n padding-left: 24px;\n }\n\n blockquote {\n padding-left: 12px;\n border-left: 3px solid ${({ theme }) => theme['202']};\n }\n\n a {\n color: ${({ theme }) => theme.primary};\n overflow-wrap: anywhere;\n }\n\n > :last-child {\n margin-bottom: 0;\n }\n`;\n"],"mappings":"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","ignoreList":[]}
|
|
@@ -3,6 +3,37 @@ import { fireEvent, render, screen, waitFor } from '@testing-library/react';
|
|
|
3
3
|
import React from 'react';
|
|
4
4
|
import { describe, expect, it, vi } from 'vitest';
|
|
5
5
|
import CopyableContent from './CopyableContent';
|
|
6
|
+
vi.mock('@chayns-components/textstring', () => ({
|
|
7
|
+
Textstring: ({
|
|
8
|
+
textstring
|
|
9
|
+
}) => textstring.fallback,
|
|
10
|
+
TextstringProvider: ({
|
|
11
|
+
children
|
|
12
|
+
}) => children,
|
|
13
|
+
ttsToITextString: textstring => textstring,
|
|
14
|
+
useTextstringValue: ({
|
|
15
|
+
textstring
|
|
16
|
+
}) => textstring.fallback
|
|
17
|
+
}));
|
|
18
|
+
const resizeObserverCallbacks = [];
|
|
19
|
+
class ResizeObserverMock {
|
|
20
|
+
constructor(callback) {
|
|
21
|
+
resizeObserverCallbacks.push(callback);
|
|
22
|
+
}
|
|
23
|
+
disconnect() {}
|
|
24
|
+
observe() {}
|
|
25
|
+
unobserve() {}
|
|
26
|
+
}
|
|
27
|
+
vi.stubGlobal('ResizeObserver', ResizeObserverMock);
|
|
28
|
+
const triggerResize = height => {
|
|
29
|
+
resizeObserverCallbacks.forEach(callback => {
|
|
30
|
+
callback([{
|
|
31
|
+
contentRect: {
|
|
32
|
+
height
|
|
33
|
+
}
|
|
34
|
+
}]);
|
|
35
|
+
});
|
|
36
|
+
};
|
|
6
37
|
vi.mock('../icon/Icon', () => ({
|
|
7
38
|
default: ({
|
|
8
39
|
icons
|
|
@@ -84,5 +115,17 @@ describe('CopyableContent', () => {
|
|
|
84
115
|
expect(container.querySelector('[data-copy-action="false"]')).toBeInTheDocument();
|
|
85
116
|
expect(container.querySelector('[data-calling-code-action="false"]')).toBeInTheDocument();
|
|
86
117
|
});
|
|
118
|
+
it('supports collapsed content', async () => {
|
|
119
|
+
render(/*#__PURE__*/React.createElement(CopyableContent, {
|
|
120
|
+
collapsedHeight: 100,
|
|
121
|
+
content: Array(20).fill('Long content').join('\n\n')
|
|
122
|
+
}));
|
|
123
|
+
triggerResize(240);
|
|
124
|
+
await waitFor(() => {
|
|
125
|
+
expect(screen.getByRole('button', {
|
|
126
|
+
name: 'Mehr'
|
|
127
|
+
})).toBeInTheDocument();
|
|
128
|
+
});
|
|
129
|
+
});
|
|
87
130
|
});
|
|
88
131
|
//# sourceMappingURL=CopyableContent.test.js.map
|
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"CopyableContent.test.js","names":["fireEvent","render","screen","waitFor","React","describe","expect","it","vi","CopyableContent","mock","default","icons","createElement","join","children","shouldShowCallingCodeAction","shouldShowCopyAction","importOriginal","createDialog","fn","open","readBlob","blob","Promise","resolve","reject","reader","FileReader","onerror","error","onload","result","readAsText","content","getByRole","name","toBeInTheDocument","toHaveAttribute","document","querySelector","not","write","spyOn","navigator","clipboard","mockResolvedValue","click","toHaveBeenCalled","item","calls","getType","resolves","toBe","container"],"sources":["../../../../src/components/copyable-content/CopyableContent.test.tsx"],"sourcesContent":["/* eslint-disable @typescript-eslint/no-unsafe-call */\nimport { fireEvent, render, screen, waitFor } from '@testing-library/react';\nimport React from 'react';\nimport { describe, expect, it, vi } from 'vitest';\nimport CopyableContent from './CopyableContent';\n\nvi.mock('../icon/Icon', () => ({\n default: ({ icons }: { icons: string[] }) => <span data-icons={icons.join(' ')} />,\n}));\n\nvi.mock('../sharing-context-menu/SharingContextMenu', () => ({\n default: ({\n children,\n shouldShowCallingCodeAction,\n shouldShowCopyAction,\n }: {\n children: React.ReactNode;\n shouldShowCallingCodeAction?: boolean;\n shouldShowCopyAction?: boolean;\n }) => (\n <div\n data-calling-code-action={shouldShowCallingCodeAction}\n data-copy-action={shouldShowCopyAction}\n >\n {children}\n </div>\n ),\n}));\n\nvi.mock('chayns-api', async (importOriginal) => ({\n ...(await importOriginal<typeof import('chayns-api')>()),\n createDialog: vi.fn(() => ({ open: vi.fn() })),\n}));\n\nconst readBlob = (blob: Blob) =>\n new Promise<string>((resolve, reject) => {\n const reader = new FileReader();\n reader.onerror = () => reject(reader.error);\n reader.onload = () => resolve(reader.result as string);\n reader.readAsText(blob);\n });\n\ndescribe('CopyableContent', () => {\n it('renders formatted markdown without active input HTML', () => {\n render(\n <CopyableContent\n content={\n '# Heading\\n\\n- Entry\\n\\n[Link](https://example.com)\\n<script onload=\"x\">bad</script>'\n }\n />,\n );\n\n expect(screen.getByRole('heading', { name: 'Heading' })).toBeInTheDocument();\n expect(screen.getByRole('link', { name: 'Link' })).toHaveAttribute(\n 'href',\n 'https://example.com',\n );\n expect(document.querySelector('script')).not.toBeInTheDocument();\n expect(document.querySelector('[onload]')).not.toBeInTheDocument();\n });\n\n it('copies content instead of custom children', async () => {\n const write = vi.spyOn(navigator.clipboard, 'write').mockResolvedValue();\n render(<CopyableContent content=\"source markdown\">Visible replacement</CopyableContent>);\n\n fireEvent.click(screen.getByRole('button', { name: 'Kopieren' }));\n\n await waitFor(() => expect(write).toHaveBeenCalled());\n const item = write.mock.calls[0][0][0] as unknown as ClipboardItem;\n await expect(readBlob(await item.getType('text/plain'))).resolves.toBe('source markdown');\n });\n\n it('shows a checkmark after a successful copy', async () => {\n vi.spyOn(navigator.clipboard, 'write').mockResolvedValue();\n const { container } = render(<CopyableContent content=\"source\" />);\n\n fireEvent.click(screen.getByRole('button', { name: 'Kopieren' }));\n\n await waitFor(() => {\n expect(container.querySelector('[data-icons=\"fa fa-check\"]')).toBeInTheDocument();\n });\n });\n\n it('offers sharing actions', () => {\n const { container } = render(<CopyableContent content=\"source\" />);\n\n expect(screen.getByRole('button', { name: 'Teilen' })).toBeInTheDocument();\n expect(container.querySelector('[data-copy-action=\"false\"]')).toBeInTheDocument();\n expect(container.querySelector('[data-calling-code-action=\"false\"]')).toBeInTheDocument();\n });\n});\n"],"mappings":"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","ignoreList":[]}
|
|
1
|
+
{"version":3,"file":"CopyableContent.test.js","names":["fireEvent","render","screen","waitFor","React","describe","expect","it","vi","CopyableContent","mock","Textstring","textstring","fallback","TextstringProvider","children","ttsToITextString","useTextstringValue","resizeObserverCallbacks","ResizeObserverMock","constructor","callback","push","disconnect","observe","unobserve","stubGlobal","triggerResize","height","forEach","contentRect","default","icons","createElement","join","shouldShowCallingCodeAction","shouldShowCopyAction","importOriginal","createDialog","fn","open","readBlob","blob","Promise","resolve","reject","reader","FileReader","onerror","error","onload","result","readAsText","content","getByRole","name","toBeInTheDocument","toHaveAttribute","document","querySelector","not","write","spyOn","navigator","clipboard","mockResolvedValue","click","toHaveBeenCalled","item","calls","getType","resolves","toBe","container","collapsedHeight","Array","fill"],"sources":["../../../../src/components/copyable-content/CopyableContent.test.tsx"],"sourcesContent":["/* eslint-disable @typescript-eslint/no-unsafe-call */\nimport { fireEvent, render, screen, waitFor } from '@testing-library/react';\nimport React from 'react';\nimport { describe, expect, it, vi } from 'vitest';\nimport CopyableContent from './CopyableContent';\n\nvi.mock('@chayns-components/textstring', () => ({\n Textstring: ({ textstring }: { textstring: { fallback: string } }) => textstring.fallback,\n TextstringProvider: ({ children }: { children: React.ReactNode }) => children,\n ttsToITextString: (textstring: { fallback: string }) => textstring,\n useTextstringValue: ({ textstring }: { textstring: { fallback: string } }) =>\n textstring.fallback,\n}));\n\ntype ResizeObserverCallback = (entries: ResizeObserverEntry[]) => void;\n\nconst resizeObserverCallbacks: ResizeObserverCallback[] = [];\n\nclass ResizeObserverMock {\n constructor(callback: ResizeObserverCallback) {\n resizeObserverCallbacks.push(callback);\n }\n\n disconnect() {}\n\n observe() {}\n\n unobserve() {}\n}\n\nvi.stubGlobal('ResizeObserver', ResizeObserverMock);\n\nconst triggerResize = (height: number) => {\n resizeObserverCallbacks.forEach((callback) => {\n callback([\n {\n contentRect: { height } as DOMRectReadOnly,\n } as ResizeObserverEntry,\n ]);\n });\n};\n\nvi.mock('../icon/Icon', () => ({\n default: ({ icons }: { icons: string[] }) => <span data-icons={icons.join(' ')} />,\n}));\n\nvi.mock('../sharing-context-menu/SharingContextMenu', () => ({\n default: ({\n children,\n shouldShowCallingCodeAction,\n shouldShowCopyAction,\n }: {\n children: React.ReactNode;\n shouldShowCallingCodeAction?: boolean;\n shouldShowCopyAction?: boolean;\n }) => (\n <div\n data-calling-code-action={shouldShowCallingCodeAction}\n data-copy-action={shouldShowCopyAction}\n >\n {children}\n </div>\n ),\n}));\n\nvi.mock('chayns-api', async (importOriginal) => ({\n ...(await importOriginal<typeof import('chayns-api')>()),\n createDialog: vi.fn(() => ({ open: vi.fn() })),\n}));\n\nconst readBlob = (blob: Blob) =>\n new Promise<string>((resolve, reject) => {\n const reader = new FileReader();\n reader.onerror = () => reject(reader.error);\n reader.onload = () => resolve(reader.result as string);\n reader.readAsText(blob);\n });\n\ndescribe('CopyableContent', () => {\n it('renders formatted markdown without active input HTML', () => {\n render(\n <CopyableContent\n content={\n '# Heading\\n\\n- Entry\\n\\n[Link](https://example.com)\\n<script onload=\"x\">bad</script>'\n }\n />,\n );\n\n expect(screen.getByRole('heading', { name: 'Heading' })).toBeInTheDocument();\n expect(screen.getByRole('link', { name: 'Link' })).toHaveAttribute(\n 'href',\n 'https://example.com',\n );\n expect(document.querySelector('script')).not.toBeInTheDocument();\n expect(document.querySelector('[onload]')).not.toBeInTheDocument();\n });\n\n it('copies content instead of custom children', async () => {\n const write = vi.spyOn(navigator.clipboard, 'write').mockResolvedValue();\n render(<CopyableContent content=\"source markdown\">Visible replacement</CopyableContent>);\n\n fireEvent.click(screen.getByRole('button', { name: 'Kopieren' }));\n\n await waitFor(() => expect(write).toHaveBeenCalled());\n const item = write.mock.calls[0][0][0] as unknown as ClipboardItem;\n await expect(readBlob(await item.getType('text/plain'))).resolves.toBe('source markdown');\n });\n\n it('shows a checkmark after a successful copy', async () => {\n vi.spyOn(navigator.clipboard, 'write').mockResolvedValue();\n const { container } = render(<CopyableContent content=\"source\" />);\n\n fireEvent.click(screen.getByRole('button', { name: 'Kopieren' }));\n\n await waitFor(() => {\n expect(container.querySelector('[data-icons=\"fa fa-check\"]')).toBeInTheDocument();\n });\n });\n\n it('offers sharing actions', () => {\n const { container } = render(<CopyableContent content=\"source\" />);\n\n expect(screen.getByRole('button', { name: 'Teilen' })).toBeInTheDocument();\n expect(container.querySelector('[data-copy-action=\"false\"]')).toBeInTheDocument();\n expect(container.querySelector('[data-calling-code-action=\"false\"]')).toBeInTheDocument();\n });\n\n it('supports collapsed content', async () => {\n render(\n <CopyableContent\n collapsedHeight={100}\n content={Array(20).fill('Long content').join('\\n\\n')}\n />,\n );\n\n triggerResize(240);\n\n await waitFor(() => {\n expect(screen.getByRole('button', { name: 'Mehr' })).toBeInTheDocument();\n });\n });\n});\n"],"mappings":"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","ignoreList":[]}
|
|
@@ -1,57 +1,69 @@
|
|
|
1
|
-
import React, { useCallback, useEffect, useLayoutEffect, useMemo, useRef, useState } from 'react';
|
|
2
|
-
import { ClampPosition } from '../../types/truncation';
|
|
3
|
-
import { debounce } from '../../utils/debounce';
|
|
4
|
-
import { truncateElement } from '../../utils/truncation';
|
|
5
|
-
import { StyledMotionTruncationContent, StyledTruncation, StyledTruncationClamp, StyledTruncationClampFocusWrapper, StyledTruncationClampWrapper, StyledTruncationPseudoContent } from './Truncation.styles';
|
|
6
1
|
import { Textstring, TextstringProvider, ttsToITextString } from '@chayns-components/textstring';
|
|
7
|
-
import
|
|
2
|
+
import React, { useCallback, useEffect, useLayoutEffect, useRef, useState } from 'react';
|
|
8
3
|
import { useKeyboardFocusHighlighting } from '../../hooks/useKeyboardFocusHighlighting';
|
|
4
|
+
import textStrings from '../../constants/textStrings';
|
|
5
|
+
import { ClampPosition } from '../../types/truncation';
|
|
6
|
+
import { StyledMotionTruncationContent, StyledTruncation, StyledTruncationClamp, StyledTruncationClampFocusWrapper, StyledTruncationClampWrapper, StyledTruncationContent } from './Truncation.styles';
|
|
9
7
|
const useIsomorphicLayoutEffect = typeof window !== 'undefined' ? useLayoutEffect : useEffect;
|
|
10
8
|
const Truncation = ({
|
|
11
9
|
collapsedHeight = 150,
|
|
12
10
|
clampPosition = ClampPosition.Right,
|
|
13
11
|
isOpen,
|
|
14
|
-
moreLabel,
|
|
15
12
|
lessLabel,
|
|
13
|
+
moreLabel,
|
|
16
14
|
onChange,
|
|
17
15
|
children,
|
|
18
16
|
shouldEnableKeyboardHighlighting
|
|
19
17
|
}) => {
|
|
20
18
|
const shouldShowKeyboardHighlighting = useKeyboardFocusHighlighting(shouldEnableKeyboardHighlighting);
|
|
21
|
-
const
|
|
22
|
-
const
|
|
23
|
-
const [
|
|
24
|
-
const [
|
|
25
|
-
const [shouldShowCollapsedElement, setShouldShowCollapsedElement] = useState(true);
|
|
26
|
-
const [hasSizeChanged, setHasSizeChanged] = useState(false);
|
|
27
|
-
const [initialRender, setInitialRender] = useState(true);
|
|
28
|
-
const [shouldSkipChangeCheck, setShouldSkipChangeCheck] = useState(false);
|
|
29
|
-
const [originalSmallHeight, setOriginalSmallHeight] = useState(0);
|
|
30
|
-
const [originalBigHeight, setOriginalBigHeight] = useState(0);
|
|
31
|
-
useEffect(() => {
|
|
32
|
-
setInitialRender(false);
|
|
33
|
-
}, []);
|
|
34
|
-
const parentRef = useRef(null);
|
|
35
|
-
const pseudoChildrenRef = useRef(null);
|
|
36
|
-
const childrenRef = useRef(null);
|
|
37
|
-
const originalChildrenRef = useRef(null);
|
|
38
|
-
const hasCollapsed = useRef(false);
|
|
39
|
-
const isAnimating = useRef(false);
|
|
40
|
-
const hasSizeRecentlyChanged = useRef(false);
|
|
41
|
-
const canResetSizeChanged = useRef(true);
|
|
19
|
+
const contentRef = useRef(null);
|
|
20
|
+
const pendingObservedHeight = useRef(0);
|
|
21
|
+
const [internalIsOpen, setInternalIsOpen] = useState(Boolean(isOpen));
|
|
22
|
+
const [contentHeight, setContentHeight] = useState(0);
|
|
42
23
|
useEffect(() => {
|
|
43
24
|
if (typeof isOpen === 'boolean') {
|
|
44
25
|
setInternalIsOpen(isOpen);
|
|
45
|
-
setShowClamp(!isOpen);
|
|
46
26
|
}
|
|
47
27
|
}, [isOpen]);
|
|
48
|
-
|
|
49
|
-
|
|
28
|
+
useIsomorphicLayoutEffect(() => {
|
|
29
|
+
if (!contentRef.current) {
|
|
30
|
+
return () => {};
|
|
31
|
+
}
|
|
32
|
+
let frame;
|
|
33
|
+
const updateContentHeight = entries => {
|
|
34
|
+
pendingObservedHeight.current = Math.max(pendingObservedHeight.current, entries?.[0]?.contentRect.height ?? 0);
|
|
35
|
+
if (frame !== undefined) {
|
|
36
|
+
return;
|
|
37
|
+
}
|
|
38
|
+
frame = window.requestAnimationFrame(() => {
|
|
39
|
+
frame = undefined;
|
|
40
|
+
if (!contentRef.current) {
|
|
41
|
+
return;
|
|
42
|
+
}
|
|
43
|
+
setContentHeight(Math.max(pendingObservedHeight.current, contentRef.current.scrollHeight, contentRef.current.getBoundingClientRect().height));
|
|
44
|
+
pendingObservedHeight.current = 0;
|
|
45
|
+
});
|
|
46
|
+
};
|
|
47
|
+
const resizeObserver = new ResizeObserver(entries => updateContentHeight(entries));
|
|
48
|
+
const mutationObserver = new MutationObserver(() => updateContentHeight());
|
|
49
|
+
resizeObserver.observe(contentRef.current);
|
|
50
|
+
mutationObserver.observe(contentRef.current, {
|
|
51
|
+
characterData: true,
|
|
52
|
+
childList: true,
|
|
53
|
+
subtree: true
|
|
54
|
+
});
|
|
55
|
+
updateContentHeight();
|
|
56
|
+
return () => {
|
|
57
|
+
resizeObserver.disconnect();
|
|
58
|
+
mutationObserver.disconnect();
|
|
59
|
+
if (frame !== undefined) {
|
|
60
|
+
window.cancelAnimationFrame(frame);
|
|
61
|
+
}
|
|
62
|
+
};
|
|
63
|
+
}, [children]);
|
|
50
64
|
const handleClampClick = useCallback(event => {
|
|
51
65
|
setInternalIsOpen(current => {
|
|
52
|
-
|
|
53
|
-
onChange(event, !current);
|
|
54
|
-
}
|
|
66
|
+
onChange?.(event, !current);
|
|
55
67
|
return !current;
|
|
56
68
|
});
|
|
57
69
|
}, [onChange]);
|
|
@@ -61,129 +73,29 @@ const Truncation = ({
|
|
|
61
73
|
event.currentTarget.click();
|
|
62
74
|
}
|
|
63
75
|
}, []);
|
|
64
|
-
useEffect(() => {
|
|
65
|
-
if (children) {
|
|
66
|
-
setShouldSkipChangeCheck(true);
|
|
67
|
-
window.setTimeout(() => {
|
|
68
|
-
setShouldSkipChangeCheck(false);
|
|
69
|
-
}, 200);
|
|
70
|
-
}
|
|
71
|
-
}, [children]);
|
|
72
|
-
const handleAnimationEnd = useCallback(() => {
|
|
73
|
-
hasCollapsed.current = true;
|
|
74
|
-
isAnimating.current = false;
|
|
75
|
-
if (canResetSizeChanged.current) {
|
|
76
|
-
setHasSizeChanged(false);
|
|
77
|
-
canResetSizeChanged.current = false;
|
|
78
|
-
}
|
|
79
|
-
window.setTimeout(() => {
|
|
80
|
-
hasSizeRecentlyChanged.current = false;
|
|
81
|
-
}, 10);
|
|
82
|
-
setShouldShowCollapsedElement(!internalIsOpen);
|
|
83
|
-
window.setTimeout(() => {
|
|
84
|
-
hasCollapsed.current = false;
|
|
85
|
-
}, 30);
|
|
86
|
-
}, [internalIsOpen]);
|
|
87
|
-
useEffect(() => {
|
|
88
|
-
if (!pseudoChildrenRef.current) {
|
|
89
|
-
return;
|
|
90
|
-
}
|
|
91
|
-
setOriginalHeight(pseudoChildrenRef.current.offsetHeight);
|
|
92
|
-
setOriginalBigHeight(pseudoChildrenRef.current.offsetHeight);
|
|
93
|
-
truncateElement(pseudoChildrenRef.current, collapsedHeight);
|
|
94
|
-
setNewCollapsedHeight(pseudoChildrenRef.current.offsetHeight);
|
|
95
|
-
setOriginalSmallHeight(pseudoChildrenRef.current.offsetHeight);
|
|
96
|
-
}, [collapsedHeight, pseudoChildrenRef, children]);
|
|
97
|
-
|
|
98
|
-
// Checks if the clamp should be shown
|
|
99
|
-
useEffect(() => {
|
|
100
|
-
if (pseudoChildrenRef.current && (!hasSizeChanged || shouldSkipChangeCheck) && !initialRender) {
|
|
101
|
-
setShowClamp(originalHeight > newCollapsedHeight);
|
|
102
|
-
}
|
|
103
|
-
}, [shouldSkipChangeCheck, collapsedHeight, hasSizeChanged, initialRender, newCollapsedHeight, originalHeight, children]);
|
|
104
|
-
useEffect(() => {
|
|
105
|
-
if (childrenRef.current && pseudoChildrenRef.current && originalChildrenRef.current) {
|
|
106
|
-
while (childrenRef.current.firstChild) {
|
|
107
|
-
childrenRef.current.removeChild(childrenRef.current.firstChild);
|
|
108
|
-
}
|
|
109
|
-
childrenRef.current.appendChild(shouldShowCollapsedElement && !internalIsOpen ? pseudoChildrenRef.current : originalChildrenRef.current);
|
|
110
|
-
parentRef.current?.appendChild(shouldShowCollapsedElement && !internalIsOpen ? originalChildrenRef.current : pseudoChildrenRef.current);
|
|
111
|
-
childrenRef.current.children[0].style.visibility = 'visible';
|
|
112
|
-
}
|
|
113
|
-
}, [children, internalIsOpen, shouldShowCollapsedElement]);
|
|
114
|
-
useIsomorphicLayoutEffect(() => {
|
|
115
|
-
if (originalChildrenRef.current) {
|
|
116
|
-
const resizeObserver = new ResizeObserver(entries => {
|
|
117
|
-
if (entries && entries[0]) {
|
|
118
|
-
const observedHeight = entries[0].contentRect.height;
|
|
119
|
-
setOriginalHeight(observedHeight < originalBigHeight ? originalBigHeight : observedHeight);
|
|
120
|
-
if (!hasCollapsed.current && !isAnimating.current && !hasSizeRecentlyChanged.current) {
|
|
121
|
-
void debounce(() => {
|
|
122
|
-
canResetSizeChanged.current = true;
|
|
123
|
-
}, 250)();
|
|
124
|
-
setHasSizeChanged(true);
|
|
125
|
-
hasSizeRecentlyChanged.current = true;
|
|
126
|
-
}
|
|
127
|
-
}
|
|
128
|
-
});
|
|
129
|
-
resizeObserver.observe(originalChildrenRef.current);
|
|
130
|
-
return () => {
|
|
131
|
-
resizeObserver.disconnect();
|
|
132
|
-
};
|
|
133
|
-
}
|
|
134
|
-
return () => {};
|
|
135
|
-
}, [originalBigHeight, children]);
|
|
136
|
-
useIsomorphicLayoutEffect(() => {
|
|
137
|
-
if (pseudoChildrenRef.current) {
|
|
138
|
-
const resizeObserver = new ResizeObserver(entries => {
|
|
139
|
-
if (entries && entries[0]) {
|
|
140
|
-
const observedHeight = entries[0].contentRect.height;
|
|
141
|
-
setNewCollapsedHeight(observedHeight < originalSmallHeight ? originalSmallHeight : observedHeight);
|
|
142
|
-
if (!hasCollapsed.current && !isAnimating.current && !hasSizeRecentlyChanged.current) {
|
|
143
|
-
void debounce(() => {
|
|
144
|
-
canResetSizeChanged.current = true;
|
|
145
|
-
}, 250)();
|
|
146
|
-
setHasSizeChanged(true);
|
|
147
|
-
hasSizeRecentlyChanged.current = true;
|
|
148
|
-
}
|
|
149
|
-
}
|
|
150
|
-
});
|
|
151
|
-
resizeObserver.observe(pseudoChildrenRef.current);
|
|
152
|
-
return () => {
|
|
153
|
-
resizeObserver.disconnect();
|
|
154
|
-
};
|
|
155
|
-
}
|
|
156
|
-
return () => {};
|
|
157
|
-
}, [originalSmallHeight, children]);
|
|
158
|
-
const ts = textStrings.components.truncation;
|
|
159
76
|
const internalMoreLabel = moreLabel ?? /*#__PURE__*/React.createElement(Textstring, {
|
|
160
|
-
textstring: ttsToITextString(
|
|
77
|
+
textstring: ttsToITextString(textStrings.components.truncation.more)
|
|
161
78
|
});
|
|
162
79
|
const internalLessLabel = lessLabel ?? /*#__PURE__*/React.createElement(Textstring, {
|
|
163
|
-
textstring: ttsToITextString(
|
|
80
|
+
textstring: ttsToITextString(textStrings.components.truncation.less)
|
|
164
81
|
});
|
|
165
|
-
|
|
166
|
-
|
|
167
|
-
|
|
168
|
-
|
|
169
|
-
|
|
170
|
-
},
|
|
171
|
-
ref: originalChildrenRef
|
|
172
|
-
}, children), /*#__PURE__*/React.createElement(StyledMotionTruncationContent, {
|
|
82
|
+
const hasOverflow = contentHeight > collapsedHeight;
|
|
83
|
+
const collapsedContentHeight = Math.min(contentHeight || collapsedHeight, collapsedHeight);
|
|
84
|
+
const targetHeight = internalIsOpen ? contentHeight || collapsedHeight : collapsedContentHeight;
|
|
85
|
+
return /*#__PURE__*/React.createElement(StyledTruncation, {
|
|
86
|
+
className: "beta-chayns-truncation"
|
|
87
|
+
}, /*#__PURE__*/React.createElement(StyledMotionTruncationContent, {
|
|
173
88
|
animate: {
|
|
174
|
-
height:
|
|
89
|
+
height: targetHeight
|
|
175
90
|
},
|
|
176
91
|
initial: false,
|
|
177
92
|
transition: {
|
|
178
93
|
type: 'tween',
|
|
179
|
-
duration:
|
|
180
|
-
}
|
|
181
|
-
|
|
182
|
-
|
|
183
|
-
|
|
184
|
-
},
|
|
185
|
-
ref: childrenRef
|
|
186
|
-
}), showClamp && /*#__PURE__*/React.createElement(StyledTruncationClampWrapper, {
|
|
94
|
+
duration: 0.2
|
|
95
|
+
}
|
|
96
|
+
}, /*#__PURE__*/React.createElement(StyledTruncationContent, {
|
|
97
|
+
ref: contentRef
|
|
98
|
+
}, children)), hasOverflow && /*#__PURE__*/React.createElement(StyledTruncationClampWrapper, {
|
|
187
99
|
$position: clampPosition
|
|
188
100
|
}, /*#__PURE__*/React.createElement(TextstringProvider, {
|
|
189
101
|
libraryName: "@chayns-components-core"
|
|
@@ -194,7 +106,7 @@ const Truncation = ({
|
|
|
194
106
|
onKeyDown: handleClampKeyDown,
|
|
195
107
|
role: "button",
|
|
196
108
|
tabIndex: 0
|
|
197
|
-
}, internalIsOpen ? internalLessLabel : internalMoreLabel)))))
|
|
109
|
+
}, internalIsOpen ? internalLessLabel : internalMoreLabel)))));
|
|
198
110
|
};
|
|
199
111
|
export default Truncation;
|
|
200
112
|
//# sourceMappingURL=Truncation.js.map
|
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"Truncation.js","names":["React","useCallback","useEffect","useLayoutEffect","useMemo","useRef","useState","ClampPosition","debounce","truncateElement","StyledMotionTruncationContent","StyledTruncation","StyledTruncationClamp","StyledTruncationClampFocusWrapper","StyledTruncationClampWrapper","StyledTruncationPseudoContent","Textstring","TextstringProvider","ttsToITextString","textStrings","useKeyboardFocusHighlighting","useIsomorphicLayoutEffect","window","Truncation","collapsedHeight","clampPosition","Right","isOpen","moreLabel","lessLabel","onChange","children","shouldEnableKeyboardHighlighting","shouldShowKeyboardHighlighting","internalIsOpen","setInternalIsOpen","showClamp","setShowClamp","newCollapsedHeight","setNewCollapsedHeight","originalHeight","setOriginalHeight","shouldShowCollapsedElement","setShouldShowCollapsedElement","hasSizeChanged","setHasSizeChanged","initialRender","setInitialRender","shouldSkipChangeCheck","setShouldSkipChangeCheck","originalSmallHeight","setOriginalSmallHeight","originalBigHeight","setOriginalBigHeight","parentRef","pseudoChildrenRef","childrenRef","originalChildrenRef","hasCollapsed","isAnimating","hasSizeRecentlyChanged","canResetSizeChanged","handleClampClick","event","current","handleClampKeyDown","key","preventDefault","currentTarget","click","setTimeout","handleAnimationEnd","offsetHeight","firstChild","removeChild","appendChild","style","visibility","resizeObserver","ResizeObserver","entries","observedHeight","contentRect","height","observe","disconnect","ts","components","truncation","internalMoreLabel","createElement","textstring","more","internalLessLabel","less","className","ref","animate","initial","transition","type","duration","onAnimationComplete","onAnimationStart","$position","libraryName","$shouldShowKeyboardHighlighting","onClick","onKeyDown","role","tabIndex"],"sources":["../../../../src/components/truncation/Truncation.tsx"],"sourcesContent":["import React, {\n FC,\n KeyboardEventHandler,\n MouseEvent,\n MouseEventHandler,\n ReactElement,\n useCallback,\n useEffect,\n useLayoutEffect,\n useMemo,\n useRef,\n useState,\n} from 'react';\nimport { ClampPosition } from '../../types/truncation';\nimport { debounce } from '../../utils/debounce';\nimport { truncateElement } from '../../utils/truncation';\nimport {\n StyledMotionTruncationContent,\n StyledTruncation,\n StyledTruncationClamp,\n StyledTruncationClampFocusWrapper,\n StyledTruncationClampWrapper,\n StyledTruncationPseudoContent,\n} from './Truncation.styles';\nimport { Textstring, TextstringProvider, ttsToITextString } from '@chayns-components/textstring';\nimport textStrings from '../../constants/textStrings';\nimport { useKeyboardFocusHighlighting } from '../../hooks/useKeyboardFocusHighlighting';\n\nexport type TruncationProps = {\n /**\n * The elements that should be expanding or collapsing.\n */\n children: ReactElement;\n /**\n * The position of the clamp.\n */\n clampPosition?: ClampPosition;\n /**\n * The height of the children Element in it`s collapsed state.\n */\n collapsedHeight?: number;\n /**\n * If set to true, the content is exposed.\n */\n isOpen?: boolean;\n /**\n * A text that should be displayed if the content is expanded.\n */\n lessLabel?: string;\n /**\n * A text that should be displayed if the content is collapsed.\n */\n moreLabel?: string;\n /**\n * Function to be executed when the component is expanding or collapsing.\n */\n onChange?: (event: MouseEvent<HTMLAnchorElement>, isOpen: boolean) => void;\n /**\n * Enables keyboard-only focus highlighting.\n */\n shouldEnableKeyboardHighlighting?: boolean;\n};\n\nconst useIsomorphicLayoutEffect = typeof window !== 'undefined' ? useLayoutEffect : useEffect;\n\nconst Truncation: FC<TruncationProps> = ({\n collapsedHeight = 150,\n clampPosition = ClampPosition.Right,\n isOpen,\n moreLabel,\n lessLabel,\n onChange,\n children,\n shouldEnableKeyboardHighlighting,\n}) => {\n const shouldShowKeyboardHighlighting = useKeyboardFocusHighlighting(\n shouldEnableKeyboardHighlighting,\n );\n\n const [internalIsOpen, setInternalIsOpen] = useState(false);\n const [showClamp, setShowClamp] = useState(true);\n const [newCollapsedHeight, setNewCollapsedHeight] = useState(collapsedHeight);\n const [originalHeight, setOriginalHeight] = useState(0);\n const [shouldShowCollapsedElement, setShouldShowCollapsedElement] = useState(true);\n const [hasSizeChanged, setHasSizeChanged] = useState(false);\n const [initialRender, setInitialRender] = useState(true);\n const [shouldSkipChangeCheck, setShouldSkipChangeCheck] = useState(false);\n\n const [originalSmallHeight, setOriginalSmallHeight] = useState(0);\n const [originalBigHeight, setOriginalBigHeight] = useState(0);\n\n useEffect(() => {\n setInitialRender(false);\n }, []);\n\n const parentRef = useRef<HTMLDivElement>(null);\n const pseudoChildrenRef = useRef<HTMLDivElement>(null);\n const childrenRef = useRef<HTMLDivElement>(null);\n const originalChildrenRef = useRef<HTMLDivElement>(null);\n const hasCollapsed = useRef(false);\n const isAnimating = useRef(false);\n const hasSizeRecentlyChanged = useRef(false);\n const canResetSizeChanged = useRef(true);\n\n useEffect(() => {\n if (typeof isOpen === 'boolean') {\n setInternalIsOpen(isOpen);\n setShowClamp(!isOpen);\n }\n }, [isOpen]);\n\n // Changes the state of the truncation\n const handleClampClick = useCallback<MouseEventHandler<HTMLAnchorElement>>(\n (event) => {\n setInternalIsOpen((current) => {\n if (typeof onChange === 'function') {\n onChange(event, !current);\n }\n\n return !current;\n });\n },\n [onChange],\n );\n\n const handleClampKeyDown = useCallback<KeyboardEventHandler<HTMLAnchorElement>>((event) => {\n if (event.key === 'Enter' || event.key === ' ') {\n event.preventDefault();\n event.currentTarget.click();\n }\n }, []);\n\n useEffect(() => {\n if (children) {\n setShouldSkipChangeCheck(true);\n\n window.setTimeout(() => {\n setShouldSkipChangeCheck(false);\n }, 200);\n }\n }, [children]);\n\n const handleAnimationEnd = useCallback(() => {\n hasCollapsed.current = true;\n isAnimating.current = false;\n\n if (canResetSizeChanged.current) {\n setHasSizeChanged(false);\n canResetSizeChanged.current = false;\n }\n\n window.setTimeout(() => {\n hasSizeRecentlyChanged.current = false;\n }, 10);\n\n setShouldShowCollapsedElement(!internalIsOpen);\n\n window.setTimeout(() => {\n hasCollapsed.current = false;\n }, 30);\n }, [internalIsOpen]);\n\n useEffect(() => {\n if (!pseudoChildrenRef.current) {\n return;\n }\n\n setOriginalHeight(pseudoChildrenRef.current.offsetHeight);\n setOriginalBigHeight(pseudoChildrenRef.current.offsetHeight);\n\n truncateElement(pseudoChildrenRef.current, collapsedHeight);\n\n setNewCollapsedHeight(pseudoChildrenRef.current.offsetHeight);\n setOriginalSmallHeight(pseudoChildrenRef.current.offsetHeight);\n }, [collapsedHeight, pseudoChildrenRef, children]);\n\n // Checks if the clamp should be shown\n useEffect(() => {\n if (\n pseudoChildrenRef.current &&\n (!hasSizeChanged || shouldSkipChangeCheck) &&\n !initialRender\n ) {\n setShowClamp(originalHeight > newCollapsedHeight);\n }\n }, [\n shouldSkipChangeCheck,\n collapsedHeight,\n hasSizeChanged,\n initialRender,\n newCollapsedHeight,\n originalHeight,\n children,\n ]);\n\n useEffect(() => {\n if (childrenRef.current && pseudoChildrenRef.current && originalChildrenRef.current) {\n while (childrenRef.current.firstChild) {\n childrenRef.current.removeChild(childrenRef.current.firstChild);\n }\n\n childrenRef.current.appendChild(\n shouldShowCollapsedElement && !internalIsOpen\n ? pseudoChildrenRef.current\n : originalChildrenRef.current,\n );\n\n parentRef.current?.appendChild(\n shouldShowCollapsedElement && !internalIsOpen\n ? originalChildrenRef.current\n : pseudoChildrenRef.current,\n );\n\n (childrenRef.current.children[0] as HTMLDivElement).style.visibility = 'visible';\n }\n }, [children, internalIsOpen, shouldShowCollapsedElement]);\n\n useIsomorphicLayoutEffect(() => {\n if (originalChildrenRef.current) {\n const resizeObserver = new ResizeObserver((entries) => {\n if (entries && entries[0]) {\n const observedHeight = entries[0].contentRect.height;\n\n setOriginalHeight(\n observedHeight < originalBigHeight ? originalBigHeight : observedHeight,\n );\n\n if (\n !hasCollapsed.current &&\n !isAnimating.current &&\n !hasSizeRecentlyChanged.current\n ) {\n void debounce(() => {\n canResetSizeChanged.current = true;\n }, 250)();\n\n setHasSizeChanged(true);\n hasSizeRecentlyChanged.current = true;\n }\n }\n });\n\n resizeObserver.observe(originalChildrenRef.current);\n\n return () => {\n resizeObserver.disconnect();\n };\n }\n\n return () => {};\n }, [originalBigHeight, children]);\n\n useIsomorphicLayoutEffect(() => {\n if (pseudoChildrenRef.current) {\n const resizeObserver = new ResizeObserver((entries) => {\n if (entries && entries[0]) {\n const observedHeight = entries[0].contentRect.height;\n\n setNewCollapsedHeight(\n observedHeight < originalSmallHeight ? originalSmallHeight : observedHeight,\n );\n\n if (\n !hasCollapsed.current &&\n !isAnimating.current &&\n !hasSizeRecentlyChanged.current\n ) {\n void debounce(() => {\n canResetSizeChanged.current = true;\n }, 250)();\n\n setHasSizeChanged(true);\n hasSizeRecentlyChanged.current = true;\n }\n }\n });\n\n resizeObserver.observe(pseudoChildrenRef.current);\n\n return () => {\n resizeObserver.disconnect();\n };\n }\n\n return () => {};\n }, [originalSmallHeight, children]);\n\n const ts = textStrings.components.truncation;\n\n const internalMoreLabel = moreLabel ?? <Textstring textstring={ttsToITextString(ts.more)} />;\n const internalLessLabel = lessLabel ?? <Textstring textstring={ttsToITextString(ts.less)} />;\n\n return useMemo(\n () => (\n <StyledTruncation className=\"beta-chayns-truncation\" ref={parentRef}>\n <StyledTruncationPseudoContent ref={pseudoChildrenRef}>\n {children}\n </StyledTruncationPseudoContent>\n <StyledTruncationPseudoContent ref={originalChildrenRef}>\n {children}\n </StyledTruncationPseudoContent>\n <StyledMotionTruncationContent\n animate={{ height: internalIsOpen ? originalHeight : newCollapsedHeight }}\n initial={false}\n transition={{ type: 'tween', duration: hasSizeChanged ? 0 : 0.2 }}\n onAnimationComplete={handleAnimationEnd}\n onAnimationStart={() => {\n isAnimating.current = true;\n }}\n ref={childrenRef}\n />\n {showClamp && (\n <StyledTruncationClampWrapper $position={clampPosition}>\n <TextstringProvider libraryName=\"@chayns-components-core\">\n <StyledTruncationClampFocusWrapper\n $shouldShowKeyboardHighlighting={shouldShowKeyboardHighlighting}\n >\n <StyledTruncationClamp\n onClick={handleClampClick}\n onKeyDown={handleClampKeyDown}\n role=\"button\"\n tabIndex={0}\n >\n {internalIsOpen ? internalLessLabel : internalMoreLabel}\n </StyledTruncationClamp>\n </StyledTruncationClampFocusWrapper>\n </TextstringProvider>\n </StyledTruncationClampWrapper>\n )}\n </StyledTruncation>\n ),\n [\n children,\n clampPosition,\n handleAnimationEnd,\n handleClampClick,\n handleClampKeyDown,\n hasSizeChanged,\n internalIsOpen,\n lessLabel,\n moreLabel,\n newCollapsedHeight,\n originalHeight,\n shouldShowKeyboardHighlighting,\n showClamp,\n ],\n );\n};\n\nexport default Truncation;\n"],"mappings":"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","ignoreList":[]}
|
|
1
|
+
{"version":3,"file":"Truncation.js","names":["Textstring","TextstringProvider","ttsToITextString","React","useCallback","useEffect","useLayoutEffect","useRef","useState","useKeyboardFocusHighlighting","textStrings","ClampPosition","StyledMotionTruncationContent","StyledTruncation","StyledTruncationClamp","StyledTruncationClampFocusWrapper","StyledTruncationClampWrapper","StyledTruncationContent","useIsomorphicLayoutEffect","window","Truncation","collapsedHeight","clampPosition","Right","isOpen","lessLabel","moreLabel","onChange","children","shouldEnableKeyboardHighlighting","shouldShowKeyboardHighlighting","contentRef","pendingObservedHeight","internalIsOpen","setInternalIsOpen","Boolean","contentHeight","setContentHeight","current","frame","updateContentHeight","entries","Math","max","contentRect","height","undefined","requestAnimationFrame","scrollHeight","getBoundingClientRect","resizeObserver","ResizeObserver","mutationObserver","MutationObserver","observe","characterData","childList","subtree","disconnect","cancelAnimationFrame","handleClampClick","event","handleClampKeyDown","key","preventDefault","currentTarget","click","internalMoreLabel","createElement","textstring","components","truncation","more","internalLessLabel","less","hasOverflow","collapsedContentHeight","min","targetHeight","className","animate","initial","transition","type","duration","ref","$position","libraryName","$shouldShowKeyboardHighlighting","onClick","onKeyDown","role","tabIndex"],"sources":["../../../../src/components/truncation/Truncation.tsx"],"sourcesContent":["import { Textstring, TextstringProvider, ttsToITextString } from '@chayns-components/textstring';\nimport React, {\n FC,\n KeyboardEventHandler,\n MouseEvent,\n MouseEventHandler,\n ReactElement,\n useCallback,\n useEffect,\n useLayoutEffect,\n useRef,\n useState,\n} from 'react';\nimport { useKeyboardFocusHighlighting } from '../../hooks/useKeyboardFocusHighlighting';\nimport textStrings from '../../constants/textStrings';\nimport { ClampPosition } from '../../types/truncation';\nimport {\n StyledMotionTruncationContent,\n StyledTruncation,\n StyledTruncationClamp,\n StyledTruncationClampFocusWrapper,\n StyledTruncationClampWrapper,\n StyledTruncationContent,\n} from './Truncation.styles';\n\nexport type TruncationProps = {\n /**\n * The elements that should be expanding or collapsing.\n */\n children: ReactElement;\n /**\n * The position of the clamp.\n */\n clampPosition?: ClampPosition;\n /**\n * The height of the children element in its collapsed state.\n */\n collapsedHeight?: number;\n /**\n * If set to true, the content is exposed.\n */\n isOpen?: boolean;\n /**\n * A text that should be displayed if the content is expanded.\n */\n lessLabel?: string;\n /**\n * A text that should be displayed if the content is collapsed.\n */\n moreLabel?: string;\n /**\n * Function to be executed when the component is expanding or collapsing.\n */\n onChange?: (event: MouseEvent<HTMLAnchorElement>, isOpen: boolean) => void;\n /**\n * Enables keyboard-only focus highlighting.\n */\n shouldEnableKeyboardHighlighting?: boolean;\n};\n\nconst useIsomorphicLayoutEffect = typeof window !== 'undefined' ? useLayoutEffect : useEffect;\n\nconst Truncation: FC<TruncationProps> = ({\n collapsedHeight = 150,\n clampPosition = ClampPosition.Right,\n isOpen,\n lessLabel,\n moreLabel,\n onChange,\n children,\n shouldEnableKeyboardHighlighting,\n}) => {\n const shouldShowKeyboardHighlighting = useKeyboardFocusHighlighting(\n shouldEnableKeyboardHighlighting,\n );\n const contentRef = useRef<HTMLDivElement>(null);\n const pendingObservedHeight = useRef(0);\n const [internalIsOpen, setInternalIsOpen] = useState(Boolean(isOpen));\n const [contentHeight, setContentHeight] = useState(0);\n\n useEffect(() => {\n if (typeof isOpen === 'boolean') {\n setInternalIsOpen(isOpen);\n }\n }, [isOpen]);\n\n useIsomorphicLayoutEffect(() => {\n if (!contentRef.current) {\n return () => {};\n }\n\n let frame: number | undefined;\n const updateContentHeight = (entries?: ResizeObserverEntry[]) => {\n pendingObservedHeight.current = Math.max(\n pendingObservedHeight.current,\n entries?.[0]?.contentRect.height ?? 0,\n );\n\n if (frame !== undefined) {\n return;\n }\n\n frame = window.requestAnimationFrame(() => {\n frame = undefined;\n\n if (!contentRef.current) {\n return;\n }\n\n setContentHeight(\n Math.max(\n pendingObservedHeight.current,\n contentRef.current.scrollHeight,\n contentRef.current.getBoundingClientRect().height,\n ),\n );\n pendingObservedHeight.current = 0;\n });\n };\n\n const resizeObserver = new ResizeObserver((entries) => updateContentHeight(entries));\n const mutationObserver = new MutationObserver(() => updateContentHeight());\n\n resizeObserver.observe(contentRef.current);\n mutationObserver.observe(contentRef.current, {\n characterData: true,\n childList: true,\n subtree: true,\n });\n updateContentHeight();\n\n return () => {\n resizeObserver.disconnect();\n mutationObserver.disconnect();\n\n if (frame !== undefined) {\n window.cancelAnimationFrame(frame);\n }\n };\n }, [children]);\n\n const handleClampClick = useCallback<MouseEventHandler<HTMLAnchorElement>>(\n (event) => {\n setInternalIsOpen((current) => {\n onChange?.(event, !current);\n return !current;\n });\n },\n [onChange],\n );\n\n const handleClampKeyDown = useCallback<KeyboardEventHandler<HTMLAnchorElement>>((event) => {\n if (event.key === 'Enter' || event.key === ' ') {\n event.preventDefault();\n event.currentTarget.click();\n }\n }, []);\n\n const internalMoreLabel = moreLabel ?? (\n <Textstring textstring={ttsToITextString(textStrings.components.truncation.more)} />\n );\n const internalLessLabel = lessLabel ?? (\n <Textstring textstring={ttsToITextString(textStrings.components.truncation.less)} />\n );\n const hasOverflow = contentHeight > collapsedHeight;\n const collapsedContentHeight = Math.min(contentHeight || collapsedHeight, collapsedHeight);\n const targetHeight = internalIsOpen ? contentHeight || collapsedHeight : collapsedContentHeight;\n\n return (\n <StyledTruncation className=\"beta-chayns-truncation\">\n <StyledMotionTruncationContent\n animate={{ height: targetHeight }}\n initial={false}\n transition={{ type: 'tween', duration: 0.2 }}\n >\n <StyledTruncationContent ref={contentRef}>{children}</StyledTruncationContent>\n </StyledMotionTruncationContent>\n {hasOverflow && (\n <StyledTruncationClampWrapper $position={clampPosition}>\n <TextstringProvider libraryName=\"@chayns-components-core\">\n <StyledTruncationClampFocusWrapper\n $shouldShowKeyboardHighlighting={shouldShowKeyboardHighlighting}\n >\n <StyledTruncationClamp\n onClick={handleClampClick}\n onKeyDown={handleClampKeyDown}\n role=\"button\"\n tabIndex={0}\n >\n {internalIsOpen ? internalLessLabel : internalMoreLabel}\n </StyledTruncationClamp>\n </StyledTruncationClampFocusWrapper>\n </TextstringProvider>\n </StyledTruncationClampWrapper>\n )}\n </StyledTruncation>\n );\n};\n\nexport default Truncation;\n"],"mappings":"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","ignoreList":[]}
|
|
@@ -12,9 +12,8 @@ export const StyledMotionTruncationContent = styled(motion.div)`
|
|
|
12
12
|
overflow: hidden;
|
|
13
13
|
position: relative;
|
|
14
14
|
`;
|
|
15
|
-
export const
|
|
16
|
-
|
|
17
|
-
position: absolute;
|
|
15
|
+
export const StyledTruncationContent = styled.div`
|
|
16
|
+
min-width: 0;
|
|
18
17
|
width: 100%;
|
|
19
18
|
`;
|
|
20
19
|
export const StyledTruncationClampWrapper = styled.div`
|
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"Truncation.styles.js","names":["motion","styled","css","ClampPosition","keyboardFocusHighlightingRingCss","StyledTruncation","div","StyledMotionTruncationContent","
|
|
1
|
+
{"version":3,"file":"Truncation.styles.js","names":["motion","styled","css","ClampPosition","keyboardFocusHighlightingRingCss","StyledTruncation","div","StyledMotionTruncationContent","StyledTruncationContent","StyledTruncationClampWrapper","$position","Left","Middle","StyledTruncationClampFocusWrapper","$shouldShowKeyboardHighlighting","StyledTruncationClamp","a"],"sources":["../../../../src/components/truncation/Truncation.styles.ts"],"sourcesContent":["import { motion } from 'motion/react';\nimport styled, { css } from 'styled-components';\nimport { ClampPosition } from '../../types/truncation';\nimport type { WithTheme } from '../color-scheme-provider/ColorSchemeProvider';\nimport { keyboardFocusHighlightingRingCss } from '../../utils/keyboardFocusHighlighting.styles';\n\nexport const StyledTruncation = styled.div`\n position: relative;\n overflow: hidden;\n`;\n\n// Fix framer-motion bug\nexport const StyledMotionTruncationContent = styled(motion.div)`\n overflow: hidden;\n position: relative;\n`;\n\nexport const StyledTruncationContent = styled.div`\n min-width: 0;\n width: 100%;\n`;\n\ntype StyledTruncationClampWrapperProps = WithTheme<{ $position: ClampPosition }>;\n\nexport const StyledTruncationClampWrapper = styled.div<StyledTruncationClampWrapperProps>`\n display: flex;\n\n ${({ $position }) => {\n switch ($position) {\n case ClampPosition.Left:\n return css`\n justify-content: left;\n `;\n case ClampPosition.Middle:\n return css`\n justify-content: center;\n `;\n default:\n return css`\n justify-content: right;\n `;\n }\n }}\n`;\n\ntype StyledTruncationClampProps = {\n $shouldShowKeyboardHighlighting: boolean;\n};\n\nexport const StyledTruncationClampFocusWrapper = styled.div<StyledTruncationClampProps>`\n display: inline-block;\n border-radius: 3px;\n\n ${({ $shouldShowKeyboardHighlighting }) =>\n $shouldShowKeyboardHighlighting &&\n css`\n &:focus-within {\n transition: none;\n ${keyboardFocusHighlightingRingCss};\n color: inherit;\n }\n `}\n`;\n\nexport const StyledTruncationClamp = styled.a`\n cursor: pointer;\n z-index: 2;\n display: inline-block;\n line-height: 1.2;\n`;\n"],"mappings":"AAAA,SAASA,MAAM,QAAQ,cAAc;AACrC,OAAOC,MAAM,IAAIC,GAAG,QAAQ,mBAAmB;AAC/C,SAASC,aAAa,QAAQ,wBAAwB;AAEtD,SAASC,gCAAgC,QAAQ,8CAA8C;AAE/F,OAAO,MAAMC,gBAAgB,GAAGJ,MAAM,CAACK,GAAG;AAC1C;AACA;AACA,CAAC;;AAED;AACA,OAAO,MAAMC,6BAA6B,GAAGN,MAAM,CAACD,MAAM,CAACM,GAAG,CAAC;AAC/D;AACA;AACA,CAAC;AAED,OAAO,MAAME,uBAAuB,GAAGP,MAAM,CAACK,GAAG;AACjD;AACA;AACA,CAAC;AAID,OAAO,MAAMG,4BAA4B,GAAGR,MAAM,CAACK,GAAsC;AACzF;AACA;AACA,MAAM,CAAC;EAAEI;AAAU,CAAC,KAAK;EACjB,QAAQA,SAAS;IACb,KAAKP,aAAa,CAACQ,IAAI;MACnB,OAAOT,GAAG;AAC1B;AACA,iBAAiB;IACL,KAAKC,aAAa,CAACS,MAAM;MACrB,OAAOV,GAAG;AAC1B;AACA,iBAAiB;IACL;MACI,OAAOA,GAAG;AAC1B;AACA,iBAAiB;EACT;AACJ,CAAC;AACL,CAAC;AAMD,OAAO,MAAMW,iCAAiC,GAAGZ,MAAM,CAACK,GAA+B;AACvF;AACA;AACA;AACA,MAAM,CAAC;EAAEQ;AAAgC,CAAC,KAClCA,+BAA+B,IAC/BZ,GAAG;AACX;AACA;AACA,kBAAkBE,gCAAgC;AAClD;AACA;AACA,SAAS;AACT,CAAC;AAED,OAAO,MAAMW,qBAAqB,GAAGd,MAAM,CAACe,CAAC;AAC7C;AACA;AACA;AACA;AACA,CAAC","ignoreList":[]}
|