@gilav21/shadcn-angular-rte 0.1.2 → 0.2.1
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/README.md +43 -27
- package/fesm2022/{gilav21-shadcn-angular-rte-docx-parser-B8BeJWtY.mjs → gilav21-shadcn-angular-rte-docx-parser-DiBPweI4.mjs} +63 -38
- package/fesm2022/gilav21-shadcn-angular-rte-docx-parser-DiBPweI4.mjs.map +1 -0
- package/fesm2022/{gilav21-shadcn-angular-rte-docx-to-editor-html-Cl9eIhkC.mjs → gilav21-shadcn-angular-rte-docx-to-editor-html-BreagmS_.mjs} +43 -33
- package/fesm2022/gilav21-shadcn-angular-rte-docx-to-editor-html-BreagmS_.mjs.map +1 -0
- package/fesm2022/{gilav21-shadcn-angular-rte-gilav21-shadcn-angular-rte-CfjU_y-y.mjs → gilav21-shadcn-angular-rte-gilav21-shadcn-angular-rte-BnEAQOuU.mjs} +3561 -1901
- package/fesm2022/gilav21-shadcn-angular-rte-gilav21-shadcn-angular-rte-BnEAQOuU.mjs.map +1 -0
- package/fesm2022/gilav21-shadcn-angular-rte-markup-safety-qJk8EoPk.mjs +69 -0
- package/fesm2022/gilav21-shadcn-angular-rte-markup-safety-qJk8EoPk.mjs.map +1 -0
- package/fesm2022/{gilav21-shadcn-angular-rte-pdf-readable-DmE-CIxv.mjs → gilav21-shadcn-angular-rte-pdf-readable-JvCpuNQH.mjs} +445 -124
- package/fesm2022/gilav21-shadcn-angular-rte-pdf-readable-JvCpuNQH.mjs.map +1 -0
- package/fesm2022/gilav21-shadcn-angular-rte.mjs +1 -1
- package/package.json +6 -2
- package/schematics/collection.json +10 -0
- package/schematics/ng-add/index.cjs +169 -0
- package/schematics/ng-add/schema.json +13 -0
- package/styles.css +2 -0
- package/types/gilav21-shadcn-angular-rte.d.ts +365 -114
- package/types/gilav21-shadcn-angular-rte.d.ts.map +1 -1
- package/fesm2022/gilav21-shadcn-angular-rte-docx-parser-B8BeJWtY.mjs.map +0 -1
- package/fesm2022/gilav21-shadcn-angular-rte-docx-to-editor-html-Cl9eIhkC.mjs.map +0 -1
- package/fesm2022/gilav21-shadcn-angular-rte-gilav21-shadcn-angular-rte-CfjU_y-y.mjs.map +0 -1
- package/fesm2022/gilav21-shadcn-angular-rte-pdf-readable-DmE-CIxv.mjs.map +0 -1
- package/theme.css +0 -159
package/README.md
CHANGED
|
@@ -12,39 +12,54 @@ fixes.
|
|
|
12
12
|
- **Angular 20 or 21** (peer `>=20.0.0 <22.0.0`). Both majors are covered by
|
|
13
13
|
the e2e suite, which installs this package's real tarball into a pristine
|
|
14
14
|
Angular 20 app and a pristine Angular 21 app and builds both.
|
|
15
|
-
- **Tailwind CSS v4**.
|
|
16
15
|
- Works in zoneless apps.
|
|
16
|
+
- **No Tailwind required.** The package ships its styles precompiled; your app
|
|
17
|
+
does not need Tailwind, PostCSS or any CSS setup of its own.
|
|
17
18
|
|
|
18
19
|
## Install
|
|
19
20
|
|
|
20
21
|
```bash
|
|
21
|
-
|
|
22
|
-
npm install -D tailwindcss @tailwindcss/postcss postcss
|
|
22
|
+
ng add @gilav21/shadcn-angular-rte
|
|
23
23
|
```
|
|
24
24
|
|
|
25
|
-
|
|
25
|
+
That installs the package and registers its stylesheet in `angular.json`.
|
|
26
|
+
Nothing else to configure.
|
|
27
|
+
|
|
28
|
+
Can't run `ng add`? Install with npm and add the stylesheet to the `styles`
|
|
29
|
+
array of your app's build target yourself:
|
|
26
30
|
|
|
27
31
|
```json
|
|
28
|
-
|
|
32
|
+
"styles": ["@gilav21/shadcn-angular-rte/styles.css", "src/styles.css"]
|
|
29
33
|
```
|
|
30
34
|
|
|
31
|
-
|
|
35
|
+
### What the stylesheet does — and doesn't — touch
|
|
36
|
+
|
|
37
|
+
`styles.css` styles only the editor and its overlays. It does **not** restyle your app:
|
|
38
|
+
|
|
39
|
+
- Tailwind's reset is scoped to the package's own elements — your `body`,
|
|
40
|
+
headings and buttons keep their styles.
|
|
41
|
+
- The design tokens (`--primary`, `--background`, …) are declared at zero
|
|
42
|
+
specificity, so tokens your app already defines — for example from
|
|
43
|
+
`npx shadcn-angular init` — win.
|
|
44
|
+
- Apps that run their own Tailwind build are fine: the package's utilities
|
|
45
|
+
coexist with yours.
|
|
46
|
+
- Text uses **your app's font** — the package sets no `font-family` of its own,
|
|
47
|
+
so it matches your typography. An app with no font set shows the browser
|
|
48
|
+
default (usually a serif); set one on `body` (for example
|
|
49
|
+
`font-family: system-ui, sans-serif`) for the familiar shadcn look.
|
|
50
|
+
|
|
51
|
+
## Themes
|
|
32
52
|
|
|
33
|
-
|
|
53
|
+
`ui-rich-text-editor` takes a `theme` input with the same presets `npx shadcn-angular
|
|
54
|
+
change-theme` offers: `zinc`, `slate`, `stone`, `gray`, `neutral`, `red`, `rose`, `orange`, `green`, `blue`, `yellow`, `violet`, `amber`.
|
|
34
55
|
|
|
35
|
-
```
|
|
36
|
-
|
|
37
|
-
@source "../node_modules/@gilav21/shadcn-angular-rte";
|
|
38
|
-
@import "@gilav21/shadcn-angular-rte/theme.css";
|
|
56
|
+
```html
|
|
57
|
+
<ui-rich-text-editor theme="violet" … />
|
|
39
58
|
```
|
|
40
59
|
|
|
41
|
-
|
|
42
|
-
|
|
43
|
-
|
|
44
|
-
- The `theme.css` import ships the design tokens (`:root` / `.dark` custom
|
|
45
|
-
properties, `@theme inline`, base layer). **Skip it if your app is already
|
|
46
|
-
CLI-initialised** (`npx shadcn-angular init` wrote the same tokens into your
|
|
47
|
-
own stylesheet, and importing both duplicates the `:root` block).
|
|
60
|
+
The preset applies to that instance only, including its menus, popovers,
|
|
61
|
+
tooltips and dialogs, and it follows `.dark` mode. Leave `theme` unset to
|
|
62
|
+
use your app's tokens.
|
|
48
63
|
|
|
49
64
|
## Usage
|
|
50
65
|
|
|
@@ -120,9 +135,9 @@ download only when a user actually imports a file.
|
|
|
120
135
|
## Locale, RTL and density
|
|
121
136
|
|
|
122
137
|
`[locale]` is set per editor instance (`locale="he"`), and RTL follows the
|
|
123
|
-
document direction. Density is driven by
|
|
124
|
-
|
|
125
|
-
|
|
138
|
+
document direction. Density is driven by CSS custom properties; override
|
|
139
|
+
`--density` (or `--density-rich-text-editor`) in your own stylesheet to scale
|
|
140
|
+
spacing.
|
|
126
141
|
|
|
127
142
|
## Selectors are fixed
|
|
128
143
|
|
|
@@ -152,13 +167,14 @@ uses. In practice:
|
|
|
152
167
|
|
|
153
168
|
## Troubleshooting
|
|
154
169
|
|
|
155
|
-
**Nothing is styled.** The
|
|
156
|
-
|
|
157
|
-
inside `node_modules`.
|
|
170
|
+
**Nothing is styled.** The stylesheet is not registered. Re-run `ng add @gilav21/shadcn-angular-rte`,
|
|
171
|
+
or check that `"@gilav21/shadcn-angular-rte/styles.css"` is in your build target's `styles` array.
|
|
158
172
|
|
|
159
|
-
**
|
|
160
|
-
|
|
161
|
-
|
|
173
|
+
**A package element looks off in my app.** Global rules your app declares
|
|
174
|
+
outside any `@layer` (say `button { padding: 1rem }`) beat the package's
|
|
175
|
+
styles, which live in cascade layers. Scope such rules to your own markup, or
|
|
176
|
+
put your global stylesheet in a layer. To restyle a package element on purpose,
|
|
177
|
+
pass classes through its `class` input.
|
|
162
178
|
|
|
163
179
|
**`npm install` fails with a peer error on `@angular/core`.** This package
|
|
164
180
|
supports Angular 20 and 21. On Angular 19 or older, use the CLI copy model
|
|
@@ -1,5 +1,5 @@
|
|
|
1
1
|
import { i as inflate } from './gilav21-shadcn-angular-rte-inflate-laXxypva.mjs';
|
|
2
|
-
import { i as isValidImageMagicBytes } from './gilav21-shadcn-angular-rte-gilav21-shadcn-angular-rte-
|
|
2
|
+
import { i as isValidImageMagicBytes } from './gilav21-shadcn-angular-rte-gilav21-shadcn-angular-rte-BnEAQOuU.mjs';
|
|
3
3
|
|
|
4
4
|
const DEFAULT_MAX_UNCOMPRESSED = 1024 * 1024 * 1024;
|
|
5
5
|
const DEFAULT_MAX_FILE_SIZE = 200 * 1024 * 1024;
|
|
@@ -279,6 +279,31 @@ const HIGHLIGHT_COLOR_MAP = {
|
|
|
279
279
|
black: '#000000',
|
|
280
280
|
white: '#FFFFFF',
|
|
281
281
|
};
|
|
282
|
+
/**
|
|
283
|
+
* OOXML `ST_HexColor`: exactly six hex digits (`auto` and anything else is not a
|
|
284
|
+
* colour). The model's colour fields hold only this form, so a value read out of
|
|
285
|
+
* the document can never carry a quote, a `;` or a `url(` into the markup.
|
|
286
|
+
*/
|
|
287
|
+
function hexColor(raw) {
|
|
288
|
+
return raw && /^[\dA-Fa-f]{6}$/.test(raw) ? `#${raw}` : undefined;
|
|
289
|
+
}
|
|
290
|
+
const TEXT_ALIGN_BY_JC = new Map([
|
|
291
|
+
['both', 'justify'], ['distribute', 'justify'],
|
|
292
|
+
['center', 'center'],
|
|
293
|
+
['left', 'left'], ['start', 'left'],
|
|
294
|
+
['right', 'right'], ['end', 'right'],
|
|
295
|
+
]);
|
|
296
|
+
const VERTICAL_ALIGN_BY_VALIGN = new Map([
|
|
297
|
+
['top', 'top'], ['center', 'middle'], ['bottom', 'bottom'],
|
|
298
|
+
]);
|
|
299
|
+
/** The CSS `text-align` keyword for an OOXML `w:jc` value, or `undefined` for a value outside the vocabulary. */
|
|
300
|
+
function textAlignFromJc(jc) {
|
|
301
|
+
return TEXT_ALIGN_BY_JC.get(jc);
|
|
302
|
+
}
|
|
303
|
+
/** The CSS `vertical-align` keyword for an OOXML `w:vAlign` value, or `undefined` for a value outside the vocabulary. */
|
|
304
|
+
function verticalAlignFromVAlign(vAlign) {
|
|
305
|
+
return VERTICAL_ALIGN_BY_VALIGN.get(vAlign);
|
|
306
|
+
}
|
|
282
307
|
function parseXml(xmlString) {
|
|
283
308
|
const parser = new DOMParser();
|
|
284
309
|
return parser.parseFromString(xmlString, 'application/xml');
|
|
@@ -393,7 +418,7 @@ function parseFontSizeAndColor(rPr, result, themeColors) {
|
|
|
393
418
|
function parseColorElement(color, themeColors) {
|
|
394
419
|
const val = getAttrVal(color, NS_W, 'val');
|
|
395
420
|
if (val && val !== 'auto')
|
|
396
|
-
return
|
|
421
|
+
return hexColor(val);
|
|
397
422
|
if (!themeColors)
|
|
398
423
|
return undefined;
|
|
399
424
|
const themeColor = getAttrVal(color, NS_W, 'themeColor');
|
|
@@ -416,16 +441,20 @@ function applyTintShade(hex, tint, shade) {
|
|
|
416
441
|
const r = Number.parseInt(hex.substring(1, 3), 16);
|
|
417
442
|
const g = Number.parseInt(hex.substring(3, 5), 16);
|
|
418
443
|
const b = Number.parseInt(hex.substring(5, 7), 16);
|
|
419
|
-
|
|
420
|
-
|
|
444
|
+
const t = tint ? hexFraction(tint) : undefined;
|
|
445
|
+
if (t !== undefined) {
|
|
421
446
|
return rgbToHex(Math.round(r + (255 - r) * t), Math.round(g + (255 - g) * t), Math.round(b + (255 - b) * t));
|
|
422
447
|
}
|
|
423
|
-
|
|
424
|
-
|
|
448
|
+
const s = shade ? hexFraction(shade) : undefined;
|
|
449
|
+
if (s !== undefined) {
|
|
425
450
|
return rgbToHex(Math.round(r * s), Math.round(g * s), Math.round(b * s));
|
|
426
451
|
}
|
|
427
452
|
return hex;
|
|
428
453
|
}
|
|
454
|
+
/** `00`-`FF` as 0-1; `undefined` for a value that is not hex, so a bad tint leaves the colour as it was. */
|
|
455
|
+
function hexFraction(value) {
|
|
456
|
+
return /^[\dA-Fa-f]{1,2}$/.test(value) ? Number.parseInt(value, 16) / 255 : undefined;
|
|
457
|
+
}
|
|
429
458
|
function rgbToHex(r, g, b) {
|
|
430
459
|
const toHex = (v) => Math.min(255, Math.max(0, v)).toString(16).padStart(2, '0');
|
|
431
460
|
return `#${toHex(r)}${toHex(g)}${toHex(b)}`;
|
|
@@ -452,15 +481,16 @@ function parseHighlightAndShading(rPr, result) {
|
|
|
452
481
|
const highlightEl = getChildNS(rPr, NS_W, 'highlight');
|
|
453
482
|
if (highlightEl) {
|
|
454
483
|
const val = getAttrVal(highlightEl, NS_W, 'val');
|
|
455
|
-
|
|
456
|
-
|
|
457
|
-
|
|
484
|
+
// An own-property lookup: `constructor` and `__proto__` are not highlight names.
|
|
485
|
+
const highlight = val && Object.hasOwn(HIGHLIGHT_COLOR_MAP, val) ? HIGHLIGHT_COLOR_MAP[val] : hexColor(val);
|
|
486
|
+
if (highlight)
|
|
487
|
+
result.highlight = highlight;
|
|
458
488
|
}
|
|
459
489
|
const shd = getChildNS(rPr, NS_W, 'shd');
|
|
460
490
|
if (shd) {
|
|
461
|
-
const fill = getAttrVal(shd, NS_W, 'fill');
|
|
462
|
-
if (fill
|
|
463
|
-
result.backgroundColor =
|
|
491
|
+
const fill = hexColor(getAttrVal(shd, NS_W, 'fill'));
|
|
492
|
+
if (fill)
|
|
493
|
+
result.backgroundColor = fill;
|
|
464
494
|
}
|
|
465
495
|
}
|
|
466
496
|
function parseVertAlignAndRtl(rPr, result) {
|
|
@@ -549,9 +579,9 @@ function parseParagraphBordersAndShading(pPr) {
|
|
|
549
579
|
const result = {};
|
|
550
580
|
const shd = getChildNS(pPr, NS_W, 'shd');
|
|
551
581
|
if (shd) {
|
|
552
|
-
const fill = getAttrVal(shd, NS_W, 'fill');
|
|
553
|
-
if (fill
|
|
554
|
-
result.shading =
|
|
582
|
+
const fill = hexColor(getAttrVal(shd, NS_W, 'fill'));
|
|
583
|
+
if (fill)
|
|
584
|
+
result.shading = fill;
|
|
555
585
|
}
|
|
556
586
|
const pBdr = getChildNS(pPr, NS_W, 'pBdr');
|
|
557
587
|
if (pBdr) {
|
|
@@ -577,8 +607,7 @@ function parseBorderSet(borderParent) {
|
|
|
577
607
|
}
|
|
578
608
|
function parseSingleBorder(el) {
|
|
579
609
|
const style = getAttrVal(el, NS_W, 'val') ?? 'single';
|
|
580
|
-
const
|
|
581
|
-
const color = colorVal && colorVal !== 'auto' ? `#${colorVal}` : '#000000';
|
|
610
|
+
const color = hexColor(getAttrVal(el, NS_W, 'color')) ?? '#000000';
|
|
582
611
|
const sizeVal = getAttrVal(el, NS_W, 'sz');
|
|
583
612
|
const size = sizeVal ? Number.parseInt(sizeVal, 10) / 8 : 1;
|
|
584
613
|
return { style, color, size };
|
|
@@ -616,9 +645,9 @@ function parseBidiAndAlignment(pPr) {
|
|
|
616
645
|
}
|
|
617
646
|
const jcEl = getChildNS(pPr, NS_W, 'jc');
|
|
618
647
|
if (jcEl) {
|
|
619
|
-
const
|
|
620
|
-
if (
|
|
621
|
-
result.alignment =
|
|
648
|
+
const alignment = textAlignFromJc(getAttrVal(jcEl, NS_W, 'val') ?? '');
|
|
649
|
+
if (alignment)
|
|
650
|
+
result.alignment = alignment;
|
|
622
651
|
}
|
|
623
652
|
return result;
|
|
624
653
|
}
|
|
@@ -968,17 +997,17 @@ function buildCellStyle(tcPr) {
|
|
|
968
997
|
let hasStyle = false;
|
|
969
998
|
const shd = getChildNS(tcPr, NS_W, 'shd');
|
|
970
999
|
if (shd) {
|
|
971
|
-
const fill = getAttrVal(shd, NS_W, 'fill');
|
|
972
|
-
if (fill
|
|
973
|
-
style.backgroundColor =
|
|
1000
|
+
const fill = hexColor(getAttrVal(shd, NS_W, 'fill'));
|
|
1001
|
+
if (fill) {
|
|
1002
|
+
style.backgroundColor = fill;
|
|
974
1003
|
hasStyle = true;
|
|
975
1004
|
}
|
|
976
1005
|
}
|
|
977
1006
|
const vAlign = getChildNS(tcPr, NS_W, 'vAlign');
|
|
978
1007
|
if (vAlign) {
|
|
979
|
-
const
|
|
980
|
-
if (
|
|
981
|
-
style.verticalAlign =
|
|
1008
|
+
const verticalAlign = verticalAlignFromVAlign(getAttrVal(vAlign, NS_W, 'val') ?? '');
|
|
1009
|
+
if (verticalAlign) {
|
|
1010
|
+
style.verticalAlign = verticalAlign;
|
|
982
1011
|
hasStyle = true;
|
|
983
1012
|
}
|
|
984
1013
|
}
|
|
@@ -1225,14 +1254,10 @@ function parseThemeColors(files) {
|
|
|
1225
1254
|
if (!el)
|
|
1226
1255
|
continue;
|
|
1227
1256
|
const srgb = getChildNS(el, NS_A, 'srgbClr');
|
|
1228
|
-
if (srgb) {
|
|
1229
|
-
map.set(name, `#${srgb.getAttribute('val') ?? '000000'}`);
|
|
1230
|
-
continue;
|
|
1231
|
-
}
|
|
1232
1257
|
const sys = getChildNS(el, NS_A, 'sysClr');
|
|
1233
|
-
|
|
1234
|
-
|
|
1235
|
-
|
|
1258
|
+
const hex = hexColor(srgb ? srgb.getAttribute('val') : sys?.getAttribute('lastClr'));
|
|
1259
|
+
if (hex)
|
|
1260
|
+
map.set(name, hex);
|
|
1236
1261
|
}
|
|
1237
1262
|
return map;
|
|
1238
1263
|
}
|
|
@@ -1370,9 +1395,9 @@ function extractParagraphStyleProps(pPr) {
|
|
|
1370
1395
|
const result = {};
|
|
1371
1396
|
const jcEl = getChildNS(pPr, NS_W, 'jc');
|
|
1372
1397
|
if (jcEl) {
|
|
1373
|
-
const
|
|
1374
|
-
if (
|
|
1375
|
-
result.alignment =
|
|
1398
|
+
const alignment = textAlignFromJc(getAttrVal(jcEl, NS_W, 'val') ?? '');
|
|
1399
|
+
if (alignment)
|
|
1400
|
+
result.alignment = alignment;
|
|
1376
1401
|
}
|
|
1377
1402
|
extractSpacingProps(pPr, result);
|
|
1378
1403
|
extractIndentProps(pPr, result);
|
|
@@ -1524,5 +1549,5 @@ function parseDocx(data) {
|
|
|
1524
1549
|
return { elements, plainText, footnotes, endnotes, comments, headers, footers };
|
|
1525
1550
|
}
|
|
1526
1551
|
|
|
1527
|
-
export { parseDocx };
|
|
1528
|
-
//# sourceMappingURL=gilav21-shadcn-angular-rte-docx-parser-
|
|
1552
|
+
export { parseDocx, textAlignFromJc, verticalAlignFromVAlign };
|
|
1553
|
+
//# sourceMappingURL=gilav21-shadcn-angular-rte-docx-parser-DiBPweI4.mjs.map
|