@phuong-tran-redoc/document-engine-angular 0.1.2 → 0.1.4
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/fesm2022/phuong-tran-redoc-document-engine-angular.mjs +46 -7
- package/fesm2022/phuong-tran-redoc-document-engine-angular.mjs.map +1 -1
- package/index.d.ts +17 -12
- package/package.json +8 -2
- package/src/lib/styles/editor-content.scss +190 -0
- package/src/lib/styles/editor-interaction.scss +281 -0
- package/src/lib/styles/index.scss +20 -14
- package/src/lib/styles/toolbar.scss +15 -0
package/index.d.ts
CHANGED
|
@@ -1010,6 +1010,14 @@ declare class SelectComponent implements AfterContentInit, OnChanges, OnDestroy,
|
|
|
1010
1010
|
static ɵcmp: i0.ɵɵComponentDeclaration<SelectComponent, "document-engine-select", never, { "value": { "alias": "value"; "required": false; }; "disabled": { "alias": "disabled"; "required": false; }; "labelMode": { "alias": "labelMode"; "required": false; }; "variant": { "alias": "variant"; "required": false; }; }, { "valueChange": "valueChange"; }, ["labelDirectives", "options"], ["[documentEngineSelectLabel]", "*"], true, never>;
|
|
1011
1011
|
}
|
|
1012
1012
|
|
|
1013
|
+
type HeadingLevel = 1 | 2 | 3 | 4 | 5 | 6;
|
|
1014
|
+
|
|
1015
|
+
interface HeadingOption {
|
|
1016
|
+
value: HeadingLevel | null;
|
|
1017
|
+
label: string;
|
|
1018
|
+
class: string;
|
|
1019
|
+
}
|
|
1020
|
+
|
|
1013
1021
|
interface ToolbarState {
|
|
1014
1022
|
isReadOnly: boolean;
|
|
1015
1023
|
canUndo: boolean;
|
|
@@ -1067,15 +1075,7 @@ declare class ToolbarComponent implements OnInit, OnDestroy {
|
|
|
1067
1075
|
value: TextCaseType;
|
|
1068
1076
|
label: string;
|
|
1069
1077
|
}[];
|
|
1070
|
-
|
|
1071
|
-
value: null;
|
|
1072
|
-
label: string;
|
|
1073
|
-
class: string;
|
|
1074
|
-
} | {
|
|
1075
|
-
value: number;
|
|
1076
|
-
label: string;
|
|
1077
|
-
class: string;
|
|
1078
|
-
})[];
|
|
1078
|
+
headingOptions: HeadingOption[];
|
|
1079
1079
|
readonly textAlignOptions: {
|
|
1080
1080
|
value: string;
|
|
1081
1081
|
label: string;
|
|
@@ -1105,6 +1105,13 @@ declare class ToolbarComponent implements OnInit, OnDestroy {
|
|
|
1105
1105
|
private updateToolbarState;
|
|
1106
1106
|
ngOnInit(): void;
|
|
1107
1107
|
ngOnDestroy(): void;
|
|
1108
|
+
/**
|
|
1109
|
+
* Read the configured heading levels off `config.heading`. It may be a boolean
|
|
1110
|
+
* (`true` = default levels, handled by buildHeadingOptions' fallback) or a
|
|
1111
|
+
* `Partial<HeadingOptions>` carrying a `levels` array. Returns undefined when no
|
|
1112
|
+
* explicit levels are set so the caller falls back to the default set.
|
|
1113
|
+
*/
|
|
1114
|
+
private resolveHeadingLevels;
|
|
1108
1115
|
runAndEmit(actionName: string, chain: () => void): void;
|
|
1109
1116
|
setFontSize(size: string | null): void;
|
|
1110
1117
|
setLineHeight(lineHeight: string | null): void;
|
|
@@ -1296,8 +1303,6 @@ interface DynamicFieldCategory {
|
|
|
1296
1303
|
fields: DynamicFieldItem[];
|
|
1297
1304
|
}
|
|
1298
1305
|
|
|
1299
|
-
type HeadingLevel = 1 | 2 | 3 | 4 | 5 | 6;
|
|
1300
|
-
|
|
1301
1306
|
declare const urlValidator: ValidatorFn;
|
|
1302
1307
|
|
|
1303
1308
|
interface LinkAttrs$2 {
|
|
@@ -1817,4 +1822,4 @@ declare class EditorBubbleMenuComponent implements OnInit, AfterViewInit, OnDest
|
|
|
1817
1822
|
}
|
|
1818
1823
|
|
|
1819
1824
|
export { ARCHIVE, ARROW_DROP_DOWN, AngularRenderer, ButtonDirective, CHECK, CLEAR_ALL, CLOSE, CODE, CharacterCountComponent, CheckboxComponent, ColorPickerComponent, ColorPickerViewComponent, DEFAULT, DEFAULT_TOOLBAR_STATE, DESCRIPTION, DYNAMIC_FORM, DocumentEditorComponent, DocumentEditorModule, DocumentEngineKit, DynamicFieldsViewComponent, EDIT, EDITOR_CONTENT_WRAPPER_CLASS, EDITOR_HTML_PREPROCESSOR, EditorBubbleMenuComponent, EditorCapabilities, ErrorMessageComponent, EventManager, FORMAT_ALIGN_CENTER, FORMAT_ALIGN_JUSTIFY, FORMAT_ALIGN_LEFT, FORMAT_ALIGN_RIGHT, FORMAT_BOLD, FORMAT_CLEAR, FORMAT_COLOR_FILL, FORMAT_COLOR_TEXT, FORMAT_INDENT_DECREASE, FORMAT_INDENT_INCREASE, FORMAT_ITALIC, FORMAT_LINE_SPACING, FORMAT_LIST_BULLETED, FORMAT_LIST_NUMBERED, FORMAT_QUOTE, FORMAT_SIZE, FORMAT_STRIKETHROUGH, FORMAT_UNDERLINE, FocusTrapService, FooterComponent, INSERT_PAGE_BREAK, IconComponent, IconRegistryService, ImageInsertViewComponent, InputDirective, LINK, LINK_OFF, LabelDirective, LinkEditViewComponent, LinkMainViewComponent, LinkPropertiesViewComponent, MARKDOWN, MATCH_CASE, PHOTO, PRINT, PopoverDirective, REDO, RESTRICT_EDIT, SEARCH, SEARCH_OFF, SETTINGS, SPECIAL_CHARACTER, SUBSCRIPT, SUPERSCRIPT, SelectComponent, SelectLabelDirective, SelectOptionDirective, SpecialCharactersViewComponent, TABLE_CELL_PROPERTY, TABLE_COLUMN, TABLE_MERGE_CELL, TABLE_PROPERTY, TABLE_ROW, TABLE_ROWS, TableCellStyleViewComponent, TableCreateViewComponent, TableMainViewComponent, TableStyleViewComponent, TemplateViewComponent, TiptapBubbleMenuDirective, TiptapDraggableDirective, TiptapEditorDirective, TiptapFloatingMenuDirective, ToggleGroupComponent, ToggleOptionDirective, ToolbarBubbleMenuComponent, ToolbarComponent, ToolbarService, UNDO, VERTICAL_ALIGN_BOTTOM, VERTICAL_ALIGN_CENTER, VERTICAL_ALIGN_TOP, buildToolbarState, selectionChangeHandler, shouldShowFnFactory, urlValidator };
|
|
1820
|
-
export type { BubbleMenuProps, BubbleMenuViewConfig, BubbleMenuViewContent, BubbleTarget, ButtonType, DocumentEngineConfig, DynamicFieldCategory, DynamicFieldItem, EditorBubbleMenuConfig, EditorHtmlPreprocessor, HeadingLevel, IconButton, ImageConfig, ImagePickHook, MediaResult, OutsideHandler, SelectButton, SelectOption, TableCreateViewData, TemplateItem, ToolbarBubbleMenuConfig, ToolbarButton, ToolbarState };
|
|
1825
|
+
export type { BubbleMenuProps, BubbleMenuViewConfig, BubbleMenuViewContent, BubbleTarget, ButtonType, DocumentEngineConfig, DynamicFieldCategory, DynamicFieldItem, EditorBubbleMenuConfig, EditorHtmlPreprocessor, HeadingLevel, HeadingOption, IconButton, ImageConfig, ImagePickHook, MediaResult, OutsideHandler, SelectButton, SelectOption, TableCreateViewData, TemplateItem, ToolbarBubbleMenuConfig, ToolbarButton, ToolbarState };
|
package/package.json
CHANGED
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
{
|
|
2
2
|
"name": "@phuong-tran-redoc/document-engine-angular",
|
|
3
|
-
"version": "0.1.
|
|
3
|
+
"version": "0.1.4",
|
|
4
4
|
"type": "module",
|
|
5
5
|
"license": "MIT",
|
|
6
6
|
"author": "Realestatedoc (Redoc)",
|
|
@@ -35,7 +35,7 @@
|
|
|
35
35
|
"dependencies": {
|
|
36
36
|
"tslib": "^2.3.0",
|
|
37
37
|
"@floating-ui/dom": "^1.7.4",
|
|
38
|
-
"@phuong-tran-redoc/document-engine-core": "0.1.
|
|
38
|
+
"@phuong-tran-redoc/document-engine-core": "0.1.4"
|
|
39
39
|
},
|
|
40
40
|
"peerDependencies": {
|
|
41
41
|
"rxjs": "^7.5.0",
|
|
@@ -75,6 +75,12 @@
|
|
|
75
75
|
"./styles": {
|
|
76
76
|
"sass": "./src/lib/styles/index.scss"
|
|
77
77
|
},
|
|
78
|
+
"./styles/editor-content": {
|
|
79
|
+
"sass": "./src/lib/styles/editor-content.scss"
|
|
80
|
+
},
|
|
81
|
+
"./styles/editor-interaction": {
|
|
82
|
+
"sass": "./src/lib/styles/editor-interaction.scss"
|
|
83
|
+
},
|
|
78
84
|
"./package.json": {
|
|
79
85
|
"default": "./package.json"
|
|
80
86
|
},
|
|
@@ -0,0 +1,190 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* Opt-in editor CONTENT prose theme
|
|
3
|
+
* `@phuong-tran-redoc/document-engine-angular/styles/editor-content`
|
|
4
|
+
*
|
|
5
|
+
* Structural correctness for the editor's *rendered content*: heading scale,
|
|
6
|
+
* bullet + ordered lists (incl. the engine's `data-list-style-type` counters),
|
|
7
|
+
* blockquote, inline code, hr, img, and block rhythm.
|
|
8
|
+
*
|
|
9
|
+
* NOT auto-imposed — the main `/styles` barrel is chrome-only, so a consumer
|
|
10
|
+
* opts in by importing THIS subpath explicitly. Token-driven: every colour /
|
|
11
|
+
* dimension resolves from a CSS custom property with a sensible fallback, so a
|
|
12
|
+
* consumer themes it purely by remapping vars (no rule-body overrides needed).
|
|
13
|
+
*
|
|
14
|
+
* Scoped to `.tiptap-editor` (the class the editor directive sets on its host),
|
|
15
|
+
* so importing it can never leak prose onto unrelated app content.
|
|
16
|
+
*/
|
|
17
|
+
|
|
18
|
+
.tiptap-editor {
|
|
19
|
+
/* --- Block rhythm --- */
|
|
20
|
+
p {
|
|
21
|
+
margin: 0.5rem 0;
|
|
22
|
+
}
|
|
23
|
+
|
|
24
|
+
p:first-of-type {
|
|
25
|
+
margin-top: 0;
|
|
26
|
+
}
|
|
27
|
+
|
|
28
|
+
p:last-of-type {
|
|
29
|
+
margin-bottom: 0;
|
|
30
|
+
}
|
|
31
|
+
|
|
32
|
+
/* --- Headings (structural floor) ---
|
|
33
|
+
* The engine emits class-less <h1>–<h6> and the host preflight strips their
|
|
34
|
+
* size, so the lib restores a token-overridable scale. Remap `--de-prose-h*`
|
|
35
|
+
* (size) and `--foreground` (colour) to theme. */
|
|
36
|
+
h1,
|
|
37
|
+
h2,
|
|
38
|
+
h3,
|
|
39
|
+
h4,
|
|
40
|
+
h5,
|
|
41
|
+
h6 {
|
|
42
|
+
font-weight: 600; // font-semibold
|
|
43
|
+
line-height: 1.25;
|
|
44
|
+
margin: 1.25rem 0 0.5rem;
|
|
45
|
+
color: var(--foreground, hsl(222.2 84% 4.9%));
|
|
46
|
+
|
|
47
|
+
&:first-child {
|
|
48
|
+
margin-top: 0;
|
|
49
|
+
}
|
|
50
|
+
}
|
|
51
|
+
|
|
52
|
+
h1 {
|
|
53
|
+
font-size: var(--de-prose-h1, 2rem);
|
|
54
|
+
}
|
|
55
|
+
|
|
56
|
+
h2 {
|
|
57
|
+
font-size: var(--de-prose-h2, 1.5rem);
|
|
58
|
+
}
|
|
59
|
+
|
|
60
|
+
h3 {
|
|
61
|
+
font-size: var(--de-prose-h3, 1.25rem);
|
|
62
|
+
}
|
|
63
|
+
|
|
64
|
+
h4 {
|
|
65
|
+
font-size: var(--de-prose-h4, 1.125rem);
|
|
66
|
+
}
|
|
67
|
+
|
|
68
|
+
h5 {
|
|
69
|
+
font-size: var(--de-prose-h5, 1rem);
|
|
70
|
+
}
|
|
71
|
+
|
|
72
|
+
h6 {
|
|
73
|
+
font-size: var(--de-prose-h6, 0.875rem);
|
|
74
|
+
}
|
|
75
|
+
|
|
76
|
+
/* --- Blockquote --- (ported from `@apply border-l-4 border-border pl-4`) */
|
|
77
|
+
blockquote {
|
|
78
|
+
border-left: 4px solid var(--border, hsl(214.3 31.8% 91.4%));
|
|
79
|
+
padding-left: 1rem; // pl-4
|
|
80
|
+
}
|
|
81
|
+
|
|
82
|
+
/* --- Horizontal rule --- (ported from `@apply border-t border-foreground`) */
|
|
83
|
+
hr {
|
|
84
|
+
border: 0;
|
|
85
|
+
border-top: 1px solid var(--foreground, hsl(222.2 84% 4.9%));
|
|
86
|
+
}
|
|
87
|
+
|
|
88
|
+
/* --- Inline code --- */
|
|
89
|
+
code {
|
|
90
|
+
background-color: var(--secondary, hsl(210 40% 96.1%));
|
|
91
|
+
color: var(--secondary-foreground, hsl(222.2 47.4% 11.2%));
|
|
92
|
+
border-radius: 0.4rem;
|
|
93
|
+
font-size: 0.85rem;
|
|
94
|
+
padding: 0.25em 0.3em;
|
|
95
|
+
}
|
|
96
|
+
|
|
97
|
+
/* --- Image --- */
|
|
98
|
+
img {
|
|
99
|
+
display: block;
|
|
100
|
+
height: auto;
|
|
101
|
+
width: 100%;
|
|
102
|
+
max-width: 100%;
|
|
103
|
+
margin: 1rem 0;
|
|
104
|
+
}
|
|
105
|
+
|
|
106
|
+
/* --- Bullet lists (structural floor) ---
|
|
107
|
+
* The host preflight kills `list-style`; the engine relies on the theme to
|
|
108
|
+
* restore markers. */
|
|
109
|
+
ul {
|
|
110
|
+
list-style: disc;
|
|
111
|
+
padding-left: 1.5rem;
|
|
112
|
+
margin: 0.5rem 0;
|
|
113
|
+
}
|
|
114
|
+
|
|
115
|
+
ul ul {
|
|
116
|
+
list-style: circle;
|
|
117
|
+
}
|
|
118
|
+
|
|
119
|
+
ul ul ul {
|
|
120
|
+
list-style: square;
|
|
121
|
+
}
|
|
122
|
+
|
|
123
|
+
ul li p {
|
|
124
|
+
margin: 0;
|
|
125
|
+
}
|
|
126
|
+
|
|
127
|
+
/* --- Ordered lists: engine-coupled counters ---
|
|
128
|
+
* The engine resets `list-style` and paints markers via CSS counters keyed off
|
|
129
|
+
* the `data-list-style-type` attribute (decimal / lower-alpha-dot /
|
|
130
|
+
* lower-alpha-parens / lower-roman-parens). A consumer cannot derive this —
|
|
131
|
+
* the lib owns it. */
|
|
132
|
+
ol[data-list-style-type] {
|
|
133
|
+
counter-reset: list-counter;
|
|
134
|
+
list-style: none;
|
|
135
|
+
padding-left: 3rem;
|
|
136
|
+
margin: 0.5rem 0;
|
|
137
|
+
}
|
|
138
|
+
|
|
139
|
+
ol[data-list-style-type] > li {
|
|
140
|
+
position: relative;
|
|
141
|
+
display: block;
|
|
142
|
+
|
|
143
|
+
&:not(:first-child) {
|
|
144
|
+
margin-top: 0.25rem;
|
|
145
|
+
}
|
|
146
|
+
}
|
|
147
|
+
|
|
148
|
+
ol[data-list-style-type] > li::before {
|
|
149
|
+
position: absolute;
|
|
150
|
+
left: -2rem;
|
|
151
|
+
width: 2rem;
|
|
152
|
+
display: inline-block;
|
|
153
|
+
text-align: left;
|
|
154
|
+
font-variant-numeric: tabular-nums;
|
|
155
|
+
font-weight: normal;
|
|
156
|
+
}
|
|
157
|
+
|
|
158
|
+
ol p {
|
|
159
|
+
margin: 0;
|
|
160
|
+
}
|
|
161
|
+
|
|
162
|
+
/* Default decimal style (1., 2., 3.) */
|
|
163
|
+
ol[data-list-style-type='decimal'] > li::before {
|
|
164
|
+
counter-increment: list-counter;
|
|
165
|
+
content: counter(list-counter) '.';
|
|
166
|
+
}
|
|
167
|
+
|
|
168
|
+
/* Lower alpha with dot style (a., b., c.) */
|
|
169
|
+
ol[data-list-style-type='lower-alpha-dot'] > li::before {
|
|
170
|
+
counter-increment: list-counter;
|
|
171
|
+
content: counter(list-counter, lower-alpha) '.';
|
|
172
|
+
}
|
|
173
|
+
|
|
174
|
+
/* Lower alpha with parentheses style ((a), (b), (c)) */
|
|
175
|
+
ol[data-list-style-type='lower-alpha-parens'] > li::before {
|
|
176
|
+
counter-increment: list-counter;
|
|
177
|
+
content: '(' counter(list-counter, lower-alpha) ')';
|
|
178
|
+
}
|
|
179
|
+
|
|
180
|
+
/* Lower roman with parentheses style ((i), (ii), (iii)) */
|
|
181
|
+
ol[data-list-style-type='lower-roman-parens'] > li::before {
|
|
182
|
+
counter-increment: list-counter;
|
|
183
|
+
content: '(' counter(list-counter, lower-roman) ')';
|
|
184
|
+
}
|
|
185
|
+
|
|
186
|
+
/* Nested list support */
|
|
187
|
+
ol[data-list-style-type] ol {
|
|
188
|
+
counter-reset: list-counter;
|
|
189
|
+
}
|
|
190
|
+
}
|
|
@@ -0,0 +1,281 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* Opt-in editor INTERACTION chrome theme
|
|
3
|
+
* `@phuong-tran-redoc/document-engine-angular/styles/editor-interaction`
|
|
4
|
+
*
|
|
5
|
+
* Editing-surface chrome for a consumer mounting a bare editor: node-view widget
|
|
6
|
+
* handles + type-around buttons, table editing (selected cell, column resize),
|
|
7
|
+
* dynamic-field nodes, restricted-editing regions, empty-state placeholders, and
|
|
8
|
+
* the selected-node outline.
|
|
9
|
+
*
|
|
10
|
+
* Separate from `editor-content` on purpose: content prose is what makes the
|
|
11
|
+
* document *render* correctly, this is what makes it *editable*. NOT auto-imposed
|
|
12
|
+
* (the main `/styles` barrel is chrome-only) — import this subpath explicitly.
|
|
13
|
+
* Token-driven with sensible fallbacks; scoped to `.tiptap-editor`.
|
|
14
|
+
*
|
|
15
|
+
* Ported from the demo app's private `_editor.scss`; Tailwind `@apply` utilities
|
|
16
|
+
* are inlined as plain CSS and the demo-only colour vars are remapped so the
|
|
17
|
+
* theme themes cleanly for any consumer:
|
|
18
|
+
* --light-blue / --light-blue-foreground → --accent / --accent-foreground
|
|
19
|
+
* --blue (hover, borders, handles) → --ring
|
|
20
|
+
* --blue (selected-node outline) → --primary
|
|
21
|
+
* --secondary (placeholder text) → --muted-foreground
|
|
22
|
+
* --green (dynamic-field accent) → --de-dynamic-field (engine custom prop)
|
|
23
|
+
*/
|
|
24
|
+
|
|
25
|
+
.tiptap-editor {
|
|
26
|
+
position: relative;
|
|
27
|
+
|
|
28
|
+
.ProseMirror {
|
|
29
|
+
&:focus-visible {
|
|
30
|
+
outline: none;
|
|
31
|
+
}
|
|
32
|
+
}
|
|
33
|
+
|
|
34
|
+
/* Selected node (covers image + any selected block) */
|
|
35
|
+
.ProseMirror-selectednode {
|
|
36
|
+
outline: 3px solid var(--primary, hsl(221.2 83.2% 53.3%));
|
|
37
|
+
}
|
|
38
|
+
|
|
39
|
+
/* Restricted-editing region (was --light-blue / --blue) */
|
|
40
|
+
.editable-region {
|
|
41
|
+
background-color: var(--accent, hsl(210 40% 96.1%));
|
|
42
|
+
color: var(--accent-foreground, hsl(222.2 47.4% 11.2%));
|
|
43
|
+
border-bottom: 1px dashed var(--ring, hsl(221.2 83.2% 53.3%));
|
|
44
|
+
padding: 0 4px;
|
|
45
|
+
}
|
|
46
|
+
|
|
47
|
+
/* Placeholder (first line) — was --secondary; use --muted-foreground so the
|
|
48
|
+
* placeholder stays legible for any consumer token set */
|
|
49
|
+
p.is-editor-empty:first-child::before {
|
|
50
|
+
color: var(--muted-foreground, hsl(215.4 16.3% 46.9%));
|
|
51
|
+
content: attr(data-placeholder);
|
|
52
|
+
float: left;
|
|
53
|
+
height: 0;
|
|
54
|
+
pointer-events: none;
|
|
55
|
+
}
|
|
56
|
+
|
|
57
|
+
/* Placeholder (every empty line) */
|
|
58
|
+
.is-empty::before {
|
|
59
|
+
color: var(--muted-foreground, hsl(215.4 16.3% 46.9%));
|
|
60
|
+
content: attr(data-placeholder);
|
|
61
|
+
float: left;
|
|
62
|
+
height: 0;
|
|
63
|
+
pointer-events: none;
|
|
64
|
+
}
|
|
65
|
+
|
|
66
|
+
/* --- Node-view widget (figure wrapper) --- */
|
|
67
|
+
.widget {
|
|
68
|
+
position: relative; // relative
|
|
69
|
+
margin: 1rem 0; // my-4 mx-0
|
|
70
|
+
transition: opacity 0.2s ease-in-out;
|
|
71
|
+
|
|
72
|
+
&:hover {
|
|
73
|
+
outline: 3px solid var(--ring, hsl(221.2 83.2% 53.3%));
|
|
74
|
+
}
|
|
75
|
+
|
|
76
|
+
&.ProseMirror-selectednode {
|
|
77
|
+
outline: 2px solid var(--accent, hsl(210 40% 96.1%));
|
|
78
|
+
outline-offset: 2px;
|
|
79
|
+
}
|
|
80
|
+
|
|
81
|
+
&:hover .widget__selection-handle {
|
|
82
|
+
opacity: 1;
|
|
83
|
+
}
|
|
84
|
+
|
|
85
|
+
&:first-child {
|
|
86
|
+
margin-top: 0;
|
|
87
|
+
}
|
|
88
|
+
|
|
89
|
+
.ck p:first-child {
|
|
90
|
+
margin-top: 0;
|
|
91
|
+
}
|
|
92
|
+
}
|
|
93
|
+
|
|
94
|
+
/* Selection handle button */
|
|
95
|
+
.widget__selection-handle {
|
|
96
|
+
position: absolute;
|
|
97
|
+
z-index: 20;
|
|
98
|
+
display: flex;
|
|
99
|
+
align-items: center;
|
|
100
|
+
justify-content: center;
|
|
101
|
+
cursor: grab;
|
|
102
|
+
width: 1.5rem; // w-6
|
|
103
|
+
height: 1.5rem; // h-6
|
|
104
|
+
border-radius: 0.25rem; // rounded
|
|
105
|
+
border: 1px solid var(--border, hsl(214.3 31.8% 91.4%));
|
|
106
|
+
background-color: var(--card, hsl(0 0% 100%));
|
|
107
|
+
color: var(--muted-foreground, hsl(215.4 16.3% 46.9%));
|
|
108
|
+
box-shadow: 0 1px 2px 0 rgba(0, 0, 0, 0.05); // shadow-elevation-1
|
|
109
|
+
|
|
110
|
+
left: -32px;
|
|
111
|
+
top: 0;
|
|
112
|
+
opacity: 0;
|
|
113
|
+
transition: opacity 0.15s ease-in-out, background-color 0.15s ease-in-out;
|
|
114
|
+
|
|
115
|
+
svg {
|
|
116
|
+
width: 20px;
|
|
117
|
+
height: 20px;
|
|
118
|
+
}
|
|
119
|
+
|
|
120
|
+
&:hover {
|
|
121
|
+
opacity: 1 !important;
|
|
122
|
+
background-color: var(--accent, hsl(210 40% 96.1%));
|
|
123
|
+
color: var(--accent-foreground, hsl(222.2 47.4% 11.2%));
|
|
124
|
+
}
|
|
125
|
+
|
|
126
|
+
&:active {
|
|
127
|
+
cursor: grabbing;
|
|
128
|
+
}
|
|
129
|
+
}
|
|
130
|
+
|
|
131
|
+
/* Widget content area */
|
|
132
|
+
.widget-content {
|
|
133
|
+
position: relative;
|
|
134
|
+
}
|
|
135
|
+
|
|
136
|
+
/* Type-around buttons (insert paragraph before/after) */
|
|
137
|
+
.type-around {
|
|
138
|
+
opacity: 0;
|
|
139
|
+
pointer-events: none;
|
|
140
|
+
transition: opacity 0.2s ease-in-out;
|
|
141
|
+
height: auto;
|
|
142
|
+
width: auto;
|
|
143
|
+
position: static;
|
|
144
|
+
}
|
|
145
|
+
|
|
146
|
+
.widget:hover > .type-around {
|
|
147
|
+
opacity: 1;
|
|
148
|
+
pointer-events: auto;
|
|
149
|
+
}
|
|
150
|
+
|
|
151
|
+
.widget__type-around__button {
|
|
152
|
+
position: relative;
|
|
153
|
+
display: flex;
|
|
154
|
+
align-items: center;
|
|
155
|
+
justify-content: center;
|
|
156
|
+
cursor: pointer;
|
|
157
|
+
width: 1.5rem; // w-6
|
|
158
|
+
height: 1.5rem; // h-6
|
|
159
|
+
border-radius: 9999px; // rounded-full
|
|
160
|
+
background-color: var(--card, hsl(0 0% 100%));
|
|
161
|
+
color: var(--muted-foreground, hsl(215.4 16.3% 46.9%));
|
|
162
|
+
border: 2px solid var(--border, hsl(214.3 31.8% 91.4%));
|
|
163
|
+
box-shadow: 0 1px 3px 0 rgba(0, 0, 0, 0.1), 0 1px 2px -1px rgba(0, 0, 0, 0.1); // shadow-elevation-2
|
|
164
|
+
transition: all 0.2s cubic-bezier(0.4, 0, 0.2, 1);
|
|
165
|
+
z-index: 20;
|
|
166
|
+
|
|
167
|
+
&:hover {
|
|
168
|
+
background-color: var(--accent, hsl(210 40% 96.1%));
|
|
169
|
+
color: var(--accent-foreground, hsl(222.2 47.4% 11.2%));
|
|
170
|
+
border-color: var(--accent, hsl(210 40% 96.1%));
|
|
171
|
+
}
|
|
172
|
+
|
|
173
|
+
&:active {
|
|
174
|
+
transform: scale(1.05);
|
|
175
|
+
}
|
|
176
|
+
|
|
177
|
+
&_before {
|
|
178
|
+
position: absolute;
|
|
179
|
+
top: -0.75rem;
|
|
180
|
+
left: 10%;
|
|
181
|
+
transform: translateX(-50%);
|
|
182
|
+
}
|
|
183
|
+
|
|
184
|
+
&_after {
|
|
185
|
+
position: absolute;
|
|
186
|
+
bottom: -0.75rem;
|
|
187
|
+
left: 90%;
|
|
188
|
+
transform: translateX(-50%);
|
|
189
|
+
}
|
|
190
|
+
|
|
191
|
+
svg {
|
|
192
|
+
width: 14px;
|
|
193
|
+
height: 14px;
|
|
194
|
+
transition: transform 0.2s ease;
|
|
195
|
+
}
|
|
196
|
+
|
|
197
|
+
&:hover svg {
|
|
198
|
+
transform: scale(1.1);
|
|
199
|
+
}
|
|
200
|
+
}
|
|
201
|
+
|
|
202
|
+
/* --- Table editing chrome --- */
|
|
203
|
+
.table-wrapper {
|
|
204
|
+
position: relative;
|
|
205
|
+
}
|
|
206
|
+
|
|
207
|
+
table {
|
|
208
|
+
width: 100%;
|
|
209
|
+
max-width: 100%;
|
|
210
|
+
border-collapse: collapse;
|
|
211
|
+
table-layout: fixed;
|
|
212
|
+
position: relative;
|
|
213
|
+
|
|
214
|
+
th,
|
|
215
|
+
td {
|
|
216
|
+
padding: 6px;
|
|
217
|
+
position: relative;
|
|
218
|
+
}
|
|
219
|
+
|
|
220
|
+
/* Selected cell (Tiptap/ProseMirror .selectedCell) */
|
|
221
|
+
.selectedCell {
|
|
222
|
+
position: relative;
|
|
223
|
+
|
|
224
|
+
&::after {
|
|
225
|
+
content: '';
|
|
226
|
+
position: absolute;
|
|
227
|
+
inset: 0;
|
|
228
|
+
z-index: 10;
|
|
229
|
+
background-color: var(--de-selected-cell, rgba(59, 130, 246, 0.12)); // bg-blue-100/50
|
|
230
|
+
pointer-events: none;
|
|
231
|
+
}
|
|
232
|
+
}
|
|
233
|
+
|
|
234
|
+
/* Column resize handle (ColumnResizing) */
|
|
235
|
+
.column-resize-handle {
|
|
236
|
+
position: absolute;
|
|
237
|
+
width: 0.25rem; // w-1
|
|
238
|
+
top: 0;
|
|
239
|
+
bottom: 0;
|
|
240
|
+
right: -0.125rem; // -right-0.5
|
|
241
|
+
background-color: var(--ring, hsl(221.2 83.2% 53.3%)); // bg-blue-300
|
|
242
|
+
pointer-events: none;
|
|
243
|
+
}
|
|
244
|
+
}
|
|
245
|
+
|
|
246
|
+
.resize-cursor {
|
|
247
|
+
cursor: col-resize;
|
|
248
|
+
}
|
|
249
|
+
|
|
250
|
+
/* Custom column-resizer handle */
|
|
251
|
+
.pm-col-resizer {
|
|
252
|
+
position: absolute;
|
|
253
|
+
top: 0;
|
|
254
|
+
z-index: 10; /* above table content */
|
|
255
|
+
display: block;
|
|
256
|
+
width: 4px;
|
|
257
|
+
background-color: var(--ring, hsl(221.2 83.2% 53.3%));
|
|
258
|
+
opacity: 0; /* hidden by default */
|
|
259
|
+
transition: opacity 0.2s;
|
|
260
|
+
cursor: col-resize;
|
|
261
|
+
height: 100%;
|
|
262
|
+
|
|
263
|
+
&:hover {
|
|
264
|
+
opacity: 1 !important;
|
|
265
|
+
}
|
|
266
|
+
}
|
|
267
|
+
|
|
268
|
+
/* --- Dynamic field node --- (accent was demo-only --green; exposed as the
|
|
269
|
+
* engine custom prop --de-dynamic-field so it stays remappable, since a shadcn
|
|
270
|
+
* consumer never defines --green) */
|
|
271
|
+
.dynamic-field {
|
|
272
|
+
border: 1px solid var(--de-dynamic-field, hsl(142.1 76.2% 36.3%));
|
|
273
|
+
cursor: default; /* feels non-editable */
|
|
274
|
+
user-select: none; /* prevent text selection inside */
|
|
275
|
+
white-space: nowrap;
|
|
276
|
+
|
|
277
|
+
&.ProseMirror-selectednode {
|
|
278
|
+
outline: 1px solid var(--ring, hsl(221.2 83.2% 53.3%));
|
|
279
|
+
}
|
|
280
|
+
}
|
|
281
|
+
}
|
|
@@ -1,22 +1,28 @@
|
|
|
1
1
|
/**
|
|
2
|
-
* Main styles entry point for @
|
|
2
|
+
* Main styles entry point for @phuong-tran-redoc/document-engine-angular
|
|
3
3
|
*
|
|
4
|
-
*
|
|
4
|
+
* This barrel ships CHROME ONLY — toolbar, buttons, select, color-picker,
|
|
5
|
+
* the document-editor wrapper, inputs, etc. It never styles the editor's
|
|
6
|
+
* rendered content, so importing it can never impose a look on your document.
|
|
5
7
|
*
|
|
6
|
-
*
|
|
7
|
-
* In your main styles.scss or styles.css:
|
|
8
|
-
* @import '@document-engine/document-engine-angular/styles';
|
|
8
|
+
* Usage in a client application:
|
|
9
9
|
*
|
|
10
|
-
*
|
|
11
|
-
*
|
|
12
|
-
* @import '@document-engine/document-engine-angular/styles/icon';
|
|
13
|
-
* @import '@document-engine/document-engine-angular/styles/toolbar';
|
|
14
|
-
* @import '@document-engine/document-engine-angular/styles/document-editor';
|
|
15
|
-
* @import '@document-engine/document-engine-angular/styles/color-picker';
|
|
10
|
+
* // Chrome (recommended baseline)
|
|
11
|
+
* @use '@phuong-tran-redoc/document-engine-angular/styles';
|
|
16
12
|
*
|
|
17
|
-
*
|
|
18
|
-
*
|
|
19
|
-
*
|
|
13
|
+
* Opt-in content / interaction themes (NOT included in this barrel — import
|
|
14
|
+
* whichever you want, then theme by remapping their CSS custom properties):
|
|
15
|
+
*
|
|
16
|
+
* // Content prose: heading scale, lists (incl. data-list-style-type counters),
|
|
17
|
+
* // blockquote, code, hr, img, block rhythm
|
|
18
|
+
* @use '@phuong-tran-redoc/document-engine-angular/styles/editor-content';
|
|
19
|
+
*
|
|
20
|
+
* // Editing-surface chrome: node-view widget handles, table editing,
|
|
21
|
+
* // dynamic fields, placeholders, selected-node outline
|
|
22
|
+
* @use '@phuong-tran-redoc/document-engine-angular/styles/editor-interaction';
|
|
23
|
+
*
|
|
24
|
+
* All styles use class/element selectors and CSS-variable-driven values, so you
|
|
25
|
+
* can also override them with your own CSS without importing these files.
|
|
20
26
|
*/
|
|
21
27
|
|
|
22
28
|
@forward 'icon';
|
|
@@ -56,3 +56,18 @@
|
|
|
56
56
|
display: none;
|
|
57
57
|
}
|
|
58
58
|
}
|
|
59
|
+
|
|
60
|
+
// Active/pressed state for toolbar toggle buttons (bold, italic, underline, lists,
|
|
61
|
+
// link, blockquote, …). The buttons apply `.active` via
|
|
62
|
+
// `[class.active]="editor.isActive(...)"`; this gives the pressed treatment so the
|
|
63
|
+
// currently-applied formatting is visible. Without it the class is set but nothing
|
|
64
|
+
// renders — the toggle never "lights up". Uses the consumer's `--primary` tokens
|
|
65
|
+
// for contrast against the toolbar surface (`--muted`); the hover selector keeps an
|
|
66
|
+
// active button highlighted while the pointer is over it.
|
|
67
|
+
document-engine-toolbar .btn.active {
|
|
68
|
+
&,
|
|
69
|
+
&:hover:not(:disabled) {
|
|
70
|
+
background-color: var(--primary, hsl(222.2 47.4% 11.2%));
|
|
71
|
+
color: var(--primary-foreground, hsl(210 40% 98%));
|
|
72
|
+
}
|
|
73
|
+
}
|