@gcforms/editor 1.0.19 → 1.0.21
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- package/CHANGELOG.md +8 -0
- package/package.json +1 -1
- package/src/Editor.tsx +1 -7
- package/src/i18n/en.json +1 -1
- package/src/i18n/fr.json +1 -1
- package/src/icons/CollapsibleIcon.tsx +13 -6
- package/src/plugins/CollapsibleExtension/Collapsible.css +20 -42
- package/src/plugins/ToolbarPlugin/index.tsx +17 -21
- package/src/tests/Editor.test.jsx +4 -9
package/CHANGELOG.md
CHANGED
|
@@ -5,6 +5,14 @@ All notable changes to this project will be documented in this file.
|
|
|
5
5
|
The format is based on [Keep a Changelog](https://keepachangelog.com/en/1.1.0/),
|
|
6
6
|
and this project adheres to [Semantic Versioning](https://semver.org/spec/v2.0.0.html).
|
|
7
7
|
|
|
8
|
+
## [1.0.21] - 2026-08-19
|
|
9
|
+
|
|
10
|
+
- Enable collapsible / details extension
|
|
11
|
+
|
|
12
|
+
## [1.0.20] - 2026-08-19
|
|
13
|
+
|
|
14
|
+
- Update collapsible / details extension styles
|
|
15
|
+
|
|
8
16
|
## [1.0.19] - 2026-08-17
|
|
9
17
|
|
|
10
18
|
- Add collapsible extension
|
package/package.json
CHANGED
package/src/Editor.tsx
CHANGED
|
@@ -36,7 +36,6 @@ interface EditorProps {
|
|
|
36
36
|
className?: string;
|
|
37
37
|
maxLength?: number;
|
|
38
38
|
enableDraggableBlocks?: boolean;
|
|
39
|
-
enableCollapsibleBlocks?: boolean;
|
|
40
39
|
|
|
41
40
|
onChange?(...args: unknown[]): unknown;
|
|
42
41
|
}
|
|
@@ -53,7 +52,6 @@ export const Editor = ({
|
|
|
53
52
|
className,
|
|
54
53
|
maxLength,
|
|
55
54
|
enableDraggableBlocks = false,
|
|
56
|
-
enableCollapsibleBlocks = false,
|
|
57
55
|
}: EditorProps) => {
|
|
58
56
|
contentLocale = contentLocale || locale;
|
|
59
57
|
|
|
@@ -76,11 +74,7 @@ export const Editor = ({
|
|
|
76
74
|
<ToolbarContext>
|
|
77
75
|
<LexicalExtensionComposer extension={editorExtension} contentEditable={null}>
|
|
78
76
|
<div className="gc-editor-container">
|
|
79
|
-
<ToolbarPlugin
|
|
80
|
-
editorId={editorId}
|
|
81
|
-
setIsLinkEditMode={setIsLinkEditMode}
|
|
82
|
-
enableCollapsibleBlocks={enableCollapsibleBlocks}
|
|
83
|
-
/>
|
|
77
|
+
<ToolbarPlugin editorId={editorId} setIsLinkEditMode={setIsLinkEditMode} />
|
|
84
78
|
<ShortcutsPlugin setIsLinkEditMode={setIsLinkEditMode} />
|
|
85
79
|
<RichTextPlugin
|
|
86
80
|
contentEditable={
|
package/src/i18n/en.json
CHANGED
package/src/i18n/fr.json
CHANGED
|
@@ -23,6 +23,6 @@
|
|
|
23
23
|
"tooltipOutdent": "Suppression d'indentation",
|
|
24
24
|
"indent": "Indentation",
|
|
25
25
|
"outdent": "Suppression d'indentation",
|
|
26
|
-
"tooltipInsertCollapsible": "
|
|
26
|
+
"tooltipInsertCollapsible": "Détails",
|
|
27
27
|
"insertCollapsible": "Insérer un conteneur réductible"
|
|
28
28
|
}
|
|
@@ -1,11 +1,18 @@
|
|
|
1
1
|
export const CollapsibleIcon = () => (
|
|
2
|
-
<svg
|
|
2
|
+
<svg width="24" height="24" viewBox="0 0 24 24" fill="none" xmlns="http://www.w3.org/2000/svg">
|
|
3
|
+
<path d="M9 6.25L3 9.5V3L9 6.25Z" fill="black" />
|
|
4
|
+
<path d="M17.5 8L14 3L21 3L17.5 8Z" fill="black" />
|
|
3
5
|
<path
|
|
4
|
-
d="
|
|
5
|
-
stroke="
|
|
6
|
-
|
|
7
|
-
|
|
8
|
-
|
|
6
|
+
d="M3 14.5H10M3 21H10M3 17.75H10"
|
|
7
|
+
stroke="#64748B"
|
|
8
|
+
stroke-width="2"
|
|
9
|
+
stroke-linecap="round"
|
|
10
|
+
/>
|
|
11
|
+
<path
|
|
12
|
+
d="M14 14.5L21 14.5M14 21H21M14 17.75L21 17.75"
|
|
13
|
+
stroke="black"
|
|
14
|
+
stroke-width="2"
|
|
15
|
+
stroke-linecap="round"
|
|
9
16
|
/>
|
|
10
17
|
</svg>
|
|
11
18
|
);
|
|
@@ -8,19 +8,20 @@
|
|
|
8
8
|
*/
|
|
9
9
|
|
|
10
10
|
.Collapsible__container {
|
|
11
|
-
background: #fcfcfc;
|
|
12
|
-
border: 1px solid #eee;
|
|
13
|
-
border-radius: 10px;
|
|
14
11
|
margin-bottom: 8px;
|
|
15
12
|
}
|
|
16
13
|
|
|
17
14
|
.Collapsible__title {
|
|
18
15
|
cursor: pointer;
|
|
19
|
-
padding: 5px 5px 5px
|
|
16
|
+
padding: 5px 5px 5px 40px;
|
|
20
17
|
position: relative;
|
|
21
|
-
font-weight: bold;
|
|
22
18
|
list-style: none;
|
|
23
19
|
outline: none;
|
|
20
|
+
font: var(--gcds-details-font-desktop);
|
|
21
|
+
text-decoration: underline;
|
|
22
|
+
color: var(--gcds-details-default-text);
|
|
23
|
+
text-decoration-thickness: var(--gcds-details-default-decoration-thickness);
|
|
24
|
+
text-underline-offset: var(--gcds-details-summary-underline-offset);
|
|
24
25
|
}
|
|
25
26
|
|
|
26
27
|
/* Lexical titles contain a paragraph. Remove its browser margin so the
|
|
@@ -43,65 +44,42 @@
|
|
|
43
44
|
}
|
|
44
45
|
|
|
45
46
|
.Collapsible__title:before {
|
|
46
|
-
|
|
47
|
-
|
|
48
|
-
|
|
49
|
-
border-
|
|
47
|
+
/* CSS triangle */
|
|
48
|
+
width: 0;
|
|
49
|
+
height: 0;
|
|
50
|
+
border-block: var(--gcds-details-summary-arrow-border-top-bottom) solid transparent;
|
|
51
|
+
border-inline-start: var(--gcds-details-summary-arrow-border-left) solid
|
|
52
|
+
var(--gcds-details-default-text);
|
|
50
53
|
display: block;
|
|
51
54
|
content: "";
|
|
52
55
|
position: absolute;
|
|
53
|
-
left:
|
|
56
|
+
left: var(--gcds-details-summary-arrow-left);
|
|
54
57
|
top: 50%;
|
|
55
|
-
transform-origin: 2px 50%;
|
|
56
58
|
transform: translateY(-50%);
|
|
57
59
|
transition: transform 0.3s ease;
|
|
58
60
|
}
|
|
59
61
|
|
|
60
62
|
.Collapsible__container[open] > .Collapsible__title:before {
|
|
63
|
+
/* CSS triangle */
|
|
61
64
|
transform: translateY(-50%) rotate(90deg);
|
|
62
65
|
}
|
|
63
66
|
|
|
64
67
|
.Collapsible__content {
|
|
68
|
+
color: var(--gcds-text-role-primary);
|
|
69
|
+
font: var(--gcds-text-size-body-desktop);
|
|
65
70
|
padding: 10px 5px 5px 20px;
|
|
66
71
|
box-sizing: border-box;
|
|
72
|
+
border-left: 5px solid var(--gcds-details-panel-border-color);
|
|
67
73
|
interpolate-size: allow-keywords;
|
|
68
74
|
overflow: hidden;
|
|
69
75
|
transition:
|
|
70
76
|
height 0.3s ease-out,
|
|
71
77
|
opacity 0.3s ease-out,
|
|
72
78
|
visibility 0.3s ease-out allow-discrete;
|
|
79
|
+
margin-left: 10px;
|
|
80
|
+
min-height: 40px;
|
|
73
81
|
}
|
|
74
82
|
|
|
75
|
-
/* Chrome uses div with hidden attribute — override display to allow animation */
|
|
76
83
|
.Collapsible__content[hidden] {
|
|
77
|
-
|
|
78
|
-
display: block;
|
|
79
|
-
height: 0;
|
|
80
|
-
opacity: 0;
|
|
81
|
-
visibility: hidden;
|
|
82
|
-
pointer-events: none;
|
|
83
|
-
transition:
|
|
84
|
-
height 0.3s ease-in,
|
|
85
|
-
opacity 0.3s ease-in,
|
|
86
|
-
visibility 0.3s ease-in allow-discrete;
|
|
87
|
-
}
|
|
88
|
-
|
|
89
|
-
/* Non-Chrome uses <details> — animate via ::details-content */
|
|
90
|
-
details.Collapsible__container::details-content {
|
|
91
|
-
interpolate-size: allow-keywords;
|
|
92
|
-
overflow: hidden;
|
|
93
|
-
transition:
|
|
94
|
-
height 0.3s ease-out,
|
|
95
|
-
opacity 0.3s ease-out,
|
|
96
|
-
content-visibility 0.3s ease-out allow-discrete;
|
|
97
|
-
}
|
|
98
|
-
|
|
99
|
-
details.Collapsible__container:not([open])::details-content {
|
|
100
|
-
height: 0;
|
|
101
|
-
opacity: 0;
|
|
102
|
-
content-visibility: hidden;
|
|
103
|
-
transition:
|
|
104
|
-
height 0.3s ease-in,
|
|
105
|
-
opacity 0.3s ease-in,
|
|
106
|
-
content-visibility 0.3s ease-in allow-discrete;
|
|
84
|
+
border-left-color: transparent;
|
|
107
85
|
}
|
|
@@ -48,11 +48,9 @@ import { CollapsibleIcon } from "../../icons/CollapsibleIcon";
|
|
|
48
48
|
export default function ToolbarPlugin({
|
|
49
49
|
editorId,
|
|
50
50
|
setIsLinkEditMode,
|
|
51
|
-
enableCollapsibleBlocks,
|
|
52
51
|
}: {
|
|
53
52
|
editorId: string;
|
|
54
53
|
setIsLinkEditMode: (isLinkEditMode: boolean) => void;
|
|
55
|
-
enableCollapsibleBlocks: boolean;
|
|
56
54
|
}) {
|
|
57
55
|
const [editor] = useLexicalComposerContext();
|
|
58
56
|
|
|
@@ -73,7 +71,7 @@ export default function ToolbarPlugin({
|
|
|
73
71
|
}
|
|
74
72
|
}, [activeEditor, setIsLinkEditMode, toolbarState.isLink]);
|
|
75
73
|
|
|
76
|
-
const toolbarItemCount =
|
|
74
|
+
const toolbarItemCount = 10;
|
|
77
75
|
|
|
78
76
|
const itemsRef = useRef<[HTMLButtonElement] | []>([]);
|
|
79
77
|
const [currentFocusIndex, setCurrentFocusIndex] = useState(0);
|
|
@@ -414,24 +412,22 @@ export default function ToolbarPlugin({
|
|
|
414
412
|
</button>
|
|
415
413
|
</ToolTip>
|
|
416
414
|
|
|
417
|
-
{
|
|
418
|
-
<
|
|
419
|
-
|
|
420
|
-
|
|
421
|
-
|
|
422
|
-
|
|
423
|
-
|
|
424
|
-
|
|
425
|
-
|
|
426
|
-
|
|
427
|
-
|
|
428
|
-
|
|
429
|
-
|
|
430
|
-
|
|
431
|
-
|
|
432
|
-
|
|
433
|
-
</ToolTip>
|
|
434
|
-
)}
|
|
415
|
+
<ToolTip text={t("tooltipInsertCollapsible")}>
|
|
416
|
+
<button
|
|
417
|
+
tabIndex={currentFocusIndex == 9 ? 0 : -1}
|
|
418
|
+
ref={(el) => {
|
|
419
|
+
const index = "button-9" as unknown as number;
|
|
420
|
+
if (el && itemsRef.current) itemsRef.current[index] = el;
|
|
421
|
+
}}
|
|
422
|
+
disabled={!isEditable}
|
|
423
|
+
onClick={() => insertCollapsible(editor)}
|
|
424
|
+
className="toolbar-item"
|
|
425
|
+
aria-label={t("insertCollapsible")}
|
|
426
|
+
data-testid="collapsible-button"
|
|
427
|
+
>
|
|
428
|
+
<CollapsibleIcon />
|
|
429
|
+
</button>
|
|
430
|
+
</ToolTip>
|
|
435
431
|
</div>
|
|
436
432
|
</>
|
|
437
433
|
);
|
|
@@ -50,9 +50,9 @@ describe("Lexical Editor", () => {
|
|
|
50
50
|
// Toolbar has aria-controls attribute
|
|
51
51
|
expect(toolbar).toHaveAttribute("aria-controls", contentArea.id);
|
|
52
52
|
|
|
53
|
-
//
|
|
54
|
-
expect(toolbarButtons).toHaveLength(
|
|
55
|
-
expect(within(toolbar).
|
|
53
|
+
// Details component is enabled by default.
|
|
54
|
+
expect(toolbarButtons).toHaveLength(10);
|
|
55
|
+
expect(within(toolbar).getByTestId("collapsible-button")).toBeInTheDocument();
|
|
56
56
|
|
|
57
57
|
// Content area has default content and attributes
|
|
58
58
|
expect(contentArea).toHaveAttribute("aria-label", "AriaLabel");
|
|
@@ -66,12 +66,7 @@ describe("Lexical Editor", () => {
|
|
|
66
66
|
it("can insert collapsible content from the toolbar", async () => {
|
|
67
67
|
const onChange = vi.fn();
|
|
68
68
|
const rendered = render(
|
|
69
|
-
<Editor
|
|
70
|
-
id="editor-test"
|
|
71
|
-
content="Here is some content"
|
|
72
|
-
onChange={onChange}
|
|
73
|
-
enableCollapsibleBlocks
|
|
74
|
-
/>
|
|
69
|
+
<Editor id="editor-test" content="Here is some content" onChange={onChange} />
|
|
75
70
|
);
|
|
76
71
|
|
|
77
72
|
await act(async () => {
|