@bloklabs/angular 1.16.1 → 2.1.0
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 +12 -0
- package/fesm2022/bloklabs-angular.mjs +330 -15
- package/package.json +2 -2
- package/types/bloklabs-angular.d.ts +76 -755
- package/fesm2022/bloklabs-angular.mjs.map +0 -1
package/README.md
CHANGED
|
@@ -49,9 +49,21 @@ onSave(data: OutputData) {
|
|
|
49
49
|
|
|
50
50
|
The component also implements `ControlValueAccessor`, so it works with `[(ngModel)]` and reactive forms.
|
|
51
51
|
|
|
52
|
+
## Page title
|
|
53
|
+
|
|
54
|
+
`<blok-title>` puts the page title in a place you choose, such as above your own page metadata. The editor needs `pageTitle` set: `<blok-title>` only moves the title. When `<blok-title>` is destroyed, the title goes back above the first block.
|
|
55
|
+
|
|
56
|
+
```html
|
|
57
|
+
<!-- imports: [BlokEditorComponent, BlokTitleComponent] -->
|
|
58
|
+
<blok-title [editor]="ed.instance()"></blok-title>
|
|
59
|
+
<app-page-metadata></app-page-metadata>
|
|
60
|
+
<blok-editor #ed="blok" [config]="{ pageTitle: true }"></blok-editor>
|
|
61
|
+
```
|
|
62
|
+
|
|
52
63
|
## Also exported
|
|
53
64
|
|
|
54
65
|
- `BlokContentDirective` (`[blokContent]`) — the mount point, if you drive the editor yourself.
|
|
66
|
+
- `BlokTitleComponent` (`<blok-title>`) — places the page title in your own layout.
|
|
55
67
|
- `injectBlocks()` — a reactive snapshot of the block tree plus a manipulation API.
|
|
56
68
|
- `createAngularBlock` — author block tools as Angular components.
|
|
57
69
|
- `provideBlok` / `BLOK_DEFAULT_CONFIG` — share default editor config through DI.
|
|
@@ -159,7 +159,7 @@ var BlokContentDirective = class BlokContentDirective {
|
|
|
159
159
|
}
|
|
160
160
|
static ɵfac = i0.ɵɵngDeclareFactory({
|
|
161
161
|
minVersion: "12.0.0",
|
|
162
|
-
version: "22.2.
|
|
162
|
+
version: "22.2.4",
|
|
163
163
|
ngImport: i0,
|
|
164
164
|
type: BlokContentDirective,
|
|
165
165
|
deps: [],
|
|
@@ -167,7 +167,7 @@ var BlokContentDirective = class BlokContentDirective {
|
|
|
167
167
|
});
|
|
168
168
|
static ɵdir = i0.ɵɵngDeclareDirective({
|
|
169
169
|
minVersion: "14.0.0",
|
|
170
|
-
version: "22.2.
|
|
170
|
+
version: "22.2.4",
|
|
171
171
|
type: BlokContentDirective,
|
|
172
172
|
isStandalone: true,
|
|
173
173
|
selector: "[blokContent]",
|
|
@@ -181,7 +181,7 @@ var BlokContentDirective = class BlokContentDirective {
|
|
|
181
181
|
};
|
|
182
182
|
i0.ɵɵngDeclareClassMetadata({
|
|
183
183
|
minVersion: "12.0.0",
|
|
184
|
-
version: "22.2.
|
|
184
|
+
version: "22.2.4",
|
|
185
185
|
ngImport: i0,
|
|
186
186
|
type: BlokContentDirective,
|
|
187
187
|
decorators: [{
|
|
@@ -413,6 +413,7 @@ const EMPTY_API = {
|
|
|
413
413
|
insertOutputData: () => [],
|
|
414
414
|
splitBlock: () => null,
|
|
415
415
|
insertInsideParent: () => null,
|
|
416
|
+
create: async () => null,
|
|
416
417
|
render: async () => void 0,
|
|
417
418
|
clear: async () => void 0,
|
|
418
419
|
isSyncingFromYjs: () => false
|
|
@@ -779,9 +780,19 @@ const createBlocksApiForEditor = (editor, onRead = () => void 0) => {
|
|
|
779
780
|
})();
|
|
780
781
|
return created === void 0 || created === null ? null : getById(created.id);
|
|
781
782
|
};
|
|
783
|
+
const create = async (spec = {}) => {
|
|
784
|
+
const { type, ...options } = spec;
|
|
785
|
+
try {
|
|
786
|
+
const created = await editor.blocks.create(type, options);
|
|
787
|
+
return getById(created.id);
|
|
788
|
+
} catch (error) {
|
|
789
|
+
if (error instanceof ToolNotFoundError || error instanceof Error && error.name === "BlockPlacementError") return null;
|
|
790
|
+
throw error;
|
|
791
|
+
}
|
|
792
|
+
};
|
|
782
793
|
const render = (data) => editor.blocks.render(data);
|
|
783
794
|
const clear = () => editor.blocks.clear();
|
|
784
|
-
const exportMarkdown = () => editor.blocks.exportMarkdown();
|
|
795
|
+
const exportMarkdown = (options) => editor.blocks.exportMarkdown(options);
|
|
785
796
|
const isSyncingFromYjs = () => {
|
|
786
797
|
onRead();
|
|
787
798
|
return editor.blocks.isSyncingFromYjs;
|
|
@@ -813,6 +824,7 @@ const createBlocksApiForEditor = (editor, onRead = () => void 0) => {
|
|
|
813
824
|
insertOutputData,
|
|
814
825
|
splitBlock,
|
|
815
826
|
insertInsideParent,
|
|
827
|
+
create,
|
|
816
828
|
render,
|
|
817
829
|
clear,
|
|
818
830
|
isSyncingFromYjs
|
|
@@ -856,8 +868,8 @@ function normalizeOutputBlock(block) {
|
|
|
856
868
|
};
|
|
857
869
|
}
|
|
858
870
|
function equalsOutputBlock(a, b) {
|
|
859
|
-
const { id: idA, lastEditedAt: _editedAtA, lastEditedBy: _editedByA, ...restA } = normalizeOutputBlock(a);
|
|
860
|
-
const { id: idB, lastEditedAt: _editedAtB, lastEditedBy: _editedByB, ...restB } = normalizeOutputBlock(b);
|
|
871
|
+
const { id: idA, lastEditedAt: _editedAtA, lastEditedBy: _editedByA, lastEditedWith: _editedWithA, createdAt: _createdAtA, createdBy: _createdByA, createdWith: _createdWithA, ...restA } = normalizeOutputBlock(a);
|
|
872
|
+
const { id: idB, lastEditedAt: _editedAtB, lastEditedBy: _editedByB, lastEditedWith: _editedWithB, createdAt: _createdAtB, createdBy: _createdByB, createdWith: _createdWithB, ...restB } = normalizeOutputBlock(b);
|
|
861
873
|
if (typeof idA === "string" && idA !== "" && typeof idB === "string" && idB !== "" && idA !== idB) return false;
|
|
862
874
|
return deepEqual(restA, restB);
|
|
863
875
|
}
|
|
@@ -873,7 +885,7 @@ function comparableBlocks(data, options) {
|
|
|
873
885
|
function equalsOutputData(a, b, options) {
|
|
874
886
|
const blocksA = comparableBlocks(a, options);
|
|
875
887
|
const blocksB = comparableBlocks(b, options);
|
|
876
|
-
return blocksA.length === blocksB.length && blocksA.every((block, index) => equalsOutputBlock(block, blocksB[index]));
|
|
888
|
+
return (a?.title || void 0) === (b?.title || void 0) && deepEqual(a?.icon ?? void 0, b?.icon ?? void 0) && blocksA.length === blocksB.length && blocksA.every((block, index) => equalsOutputBlock(block, blocksB[index]));
|
|
877
889
|
}
|
|
878
890
|
function createEmittedEchoWindow(capacity = 20) {
|
|
879
891
|
const emitted = [];
|
|
@@ -901,11 +913,211 @@ function isEmptyValue(value) {
|
|
|
901
913
|
if (typeof value === "object") return Object.values(value).every(isEmptyValue);
|
|
902
914
|
return true;
|
|
903
915
|
}
|
|
916
|
+
const COLOR_PRESETS = [
|
|
917
|
+
{
|
|
918
|
+
name: "gray",
|
|
919
|
+
text: "#787774",
|
|
920
|
+
bg: "#f1f1ef"
|
|
921
|
+
},
|
|
922
|
+
{
|
|
923
|
+
name: "brown",
|
|
924
|
+
text: "#9f6b53",
|
|
925
|
+
bg: "#f4eeee"
|
|
926
|
+
},
|
|
927
|
+
{
|
|
928
|
+
name: "orange",
|
|
929
|
+
text: "#d9730d",
|
|
930
|
+
bg: "#fbecdd"
|
|
931
|
+
},
|
|
932
|
+
{
|
|
933
|
+
name: "yellow",
|
|
934
|
+
text: "#cb9b00",
|
|
935
|
+
bg: "#fbf3db"
|
|
936
|
+
},
|
|
937
|
+
{
|
|
938
|
+
name: "green",
|
|
939
|
+
text: "#448361",
|
|
940
|
+
bg: "#edf3ec"
|
|
941
|
+
},
|
|
942
|
+
{
|
|
943
|
+
name: "blue",
|
|
944
|
+
text: "#337ea9",
|
|
945
|
+
bg: "#e7f3f8"
|
|
946
|
+
},
|
|
947
|
+
{
|
|
948
|
+
name: "purple",
|
|
949
|
+
text: "#9065b0",
|
|
950
|
+
bg: "#f6f3f9"
|
|
951
|
+
},
|
|
952
|
+
{
|
|
953
|
+
name: "pink",
|
|
954
|
+
text: "#c14c8a",
|
|
955
|
+
bg: "#f9f0f5"
|
|
956
|
+
},
|
|
957
|
+
{
|
|
958
|
+
name: "red",
|
|
959
|
+
text: "#d44c47",
|
|
960
|
+
bg: "#fdebec"
|
|
961
|
+
}
|
|
962
|
+
];
|
|
963
|
+
const NUM = "[+-]?(?:\\d+(?:\\.\\d+)?|\\.\\d+)";
|
|
964
|
+
const NUM_PCT = `${NUM}%?`;
|
|
965
|
+
const PCT = `${NUM}%`;
|
|
966
|
+
const HUE = `${NUM}(?:deg|grad|rad|turn)?`;
|
|
967
|
+
const COMMA = " *, *";
|
|
968
|
+
const SPACE = " +";
|
|
969
|
+
const SPACE_ALPHA = `(?: */ *${NUM_PCT})?`;
|
|
970
|
+
new RegExp(`^rgba?\\( *${NUM_PCT}${COMMA}${NUM_PCT}${COMMA}${NUM_PCT}(?:${COMMA}${NUM_PCT})? *\\)$`, "i");
|
|
971
|
+
new RegExp(`^rgba?\\( *${NUM_PCT}${SPACE}${NUM_PCT}${SPACE}${NUM_PCT}${SPACE_ALPHA} *\\)$`, "i");
|
|
972
|
+
new RegExp(`^hsla?\\( *${HUE}${COMMA}${PCT}${COMMA}${PCT}(?:${COMMA}${NUM_PCT})? *\\)$`, "i");
|
|
973
|
+
new RegExp(`^hsla?\\( *${HUE}${SPACE}${NUM_PCT}${SPACE}${NUM_PCT}${SPACE_ALPHA} *\\)$`, "i");
|
|
974
|
+
const DEFAULT_LINK_TARGET = "_blank";
|
|
975
|
+
const DEFAULT_LINK_REL = "nofollow";
|
|
976
|
+
const SAME_PAGE_LINK_TARGET = "_self";
|
|
977
|
+
const DEFAULT_HIGHLIGHT_BACKGROUND = "yellow";
|
|
978
|
+
new Set(COLOR_PRESETS.map((preset) => preset.name));
|
|
979
|
+
const PRESET_NAMES = COLOR_PRESETS.map((preset) => `"${preset.name}"`).join(", ");
|
|
980
|
+
const RICH_TEXT_MARKS = {
|
|
981
|
+
type: "object",
|
|
982
|
+
description: "Formatting on one run. Unknown keys drop, except custom `tag:<name>` marks.",
|
|
983
|
+
properties: {
|
|
984
|
+
bold: { const: true },
|
|
985
|
+
italic: { const: true },
|
|
986
|
+
underline: { const: true },
|
|
987
|
+
strikethrough: { const: true },
|
|
988
|
+
code: { const: true },
|
|
989
|
+
sup: {
|
|
990
|
+
const: true,
|
|
991
|
+
description: "Not with sub on one run."
|
|
992
|
+
},
|
|
993
|
+
sub: { const: true },
|
|
994
|
+
highlight: {
|
|
995
|
+
const: true,
|
|
996
|
+
description: `Stored as background "${DEFAULT_HIGHLIGHT_BACKGROUND}" unless background is set.`
|
|
997
|
+
},
|
|
998
|
+
color: {
|
|
999
|
+
type: "string",
|
|
1000
|
+
description: `${PRESET_NAMES}. Hex, rgb, hsl snap to the nearest; names and var() stay; other syntaxes drop.`
|
|
1001
|
+
},
|
|
1002
|
+
background: {
|
|
1003
|
+
type: "string",
|
|
1004
|
+
description: "Like color; page backgrounds drop."
|
|
1005
|
+
},
|
|
1006
|
+
link: {
|
|
1007
|
+
type: "object",
|
|
1008
|
+
description: `Default "${DEFAULT_LINK_TARGET}"/"${DEFAULT_LINK_REL}", "${SAME_PAGE_LINK_TARGET}" for #anchors.`,
|
|
1009
|
+
required: ["href"],
|
|
1010
|
+
additionalProperties: false,
|
|
1011
|
+
properties: {
|
|
1012
|
+
href: { type: "string" },
|
|
1013
|
+
target: { type: "string" },
|
|
1014
|
+
rel: { type: "string" }
|
|
1015
|
+
}
|
|
1016
|
+
}
|
|
1017
|
+
},
|
|
1018
|
+
patternProperties: { "^tag:": {
|
|
1019
|
+
type: "object",
|
|
1020
|
+
additionalProperties: { type: "string" }
|
|
1021
|
+
} }
|
|
1022
|
+
};
|
|
1023
|
+
const TEXT_SEGMENT = {
|
|
1024
|
+
type: "object",
|
|
1025
|
+
required: ["text"],
|
|
1026
|
+
additionalProperties: false,
|
|
1027
|
+
properties: {
|
|
1028
|
+
text: {
|
|
1029
|
+
type: "string",
|
|
1030
|
+
description: "Line breaks are \"\\n\"."
|
|
1031
|
+
},
|
|
1032
|
+
marks: RICH_TEXT_MARKS
|
|
1033
|
+
}
|
|
1034
|
+
};
|
|
1035
|
+
const EMBED_SEGMENT = {
|
|
1036
|
+
type: "object",
|
|
1037
|
+
required: ["embed"],
|
|
1038
|
+
additionalProperties: false,
|
|
1039
|
+
properties: {
|
|
1040
|
+
embed: { oneOf: [
|
|
1041
|
+
{
|
|
1042
|
+
type: "object",
|
|
1043
|
+
required: ["equation"],
|
|
1044
|
+
additionalProperties: false,
|
|
1045
|
+
properties: { equation: {
|
|
1046
|
+
type: "object",
|
|
1047
|
+
required: ["expression"],
|
|
1048
|
+
additionalProperties: false,
|
|
1049
|
+
properties: { expression: {
|
|
1050
|
+
type: "string",
|
|
1051
|
+
description: "LaTeX."
|
|
1052
|
+
} }
|
|
1053
|
+
} }
|
|
1054
|
+
},
|
|
1055
|
+
{
|
|
1056
|
+
type: "object",
|
|
1057
|
+
required: ["page"],
|
|
1058
|
+
additionalProperties: false,
|
|
1059
|
+
properties: { page: {
|
|
1060
|
+
type: "object",
|
|
1061
|
+
required: ["id"],
|
|
1062
|
+
additionalProperties: false,
|
|
1063
|
+
properties: { id: { type: "string" } }
|
|
1064
|
+
} }
|
|
1065
|
+
},
|
|
1066
|
+
{
|
|
1067
|
+
type: "object",
|
|
1068
|
+
required: ["html"],
|
|
1069
|
+
additionalProperties: false,
|
|
1070
|
+
properties: { html: {
|
|
1071
|
+
type: "string",
|
|
1072
|
+
description: "Kept verbatim."
|
|
1073
|
+
} }
|
|
1074
|
+
}
|
|
1075
|
+
] },
|
|
1076
|
+
marks: RICH_TEXT_MARKS
|
|
1077
|
+
}
|
|
1078
|
+
};
|
|
1079
|
+
const richText = (description) => ({
|
|
1080
|
+
description,
|
|
1081
|
+
oneOf: [{
|
|
1082
|
+
type: "array",
|
|
1083
|
+
description: "Rich-text segments, in order. Preferred: this is the shape Blok saves.",
|
|
1084
|
+
items: { anyOf: [TEXT_SEGMENT, EMBED_SEGMENT] }
|
|
1085
|
+
}, {
|
|
1086
|
+
type: "string",
|
|
1087
|
+
description: "In saved data, inline HTML. An agent command stores a string as plain text, tags and all: use segments for formatting."
|
|
1088
|
+
}]
|
|
1089
|
+
});
|
|
1090
|
+
[
|
|
1091
|
+
"Rich text is a list of segments: { text, marks? } or { embed, marks? }. A plain string is plain text, HTML tags included.",
|
|
1092
|
+
`Marks: ${Object.keys(RICH_TEXT_MARKS.properties).join(", ")}, and tag:<name> for a custom inline tool. sup and sub cannot share a run.`,
|
|
1093
|
+
`highlight alone is stored as background "${DEFAULT_HIGHLIGHT_BACKGROUND}"; with a background, as that background. color and background take a preset: ${PRESET_NAMES}. Hex, rgb and hsl are stored as the nearest preset. A CSS colour name is lowercased and kept, and so is var(--name). Other syntaxes (oklch, lab, hwb, color()) are dropped, as are a transparent colour and a white or dark-grey page background.`,
|
|
1094
|
+
`A link needs href. With no target or rel it gets target "${DEFAULT_LINK_TARGET}" and rel "${DEFAULT_LINK_REL}"; an "#anchor" href gets target "${SAME_PAGE_LINK_TARGET}". A target or rel you give is kept, but in the editor a host link config replaces both.`,
|
|
1095
|
+
"Embeds: { equation: { expression } } is inline LaTeX; { page: { id } } mentions a page: id is the pageId in a page block's data, not the block id.",
|
|
1096
|
+
"text.format with unset [\"*\"] clears every mark; \"tag:*\" clears every custom mark.",
|
|
1097
|
+
"markdown.insert cannot write underline, sup, sub, highlight or colours: insert the text, then use text.format."
|
|
1098
|
+
].join("\n");
|
|
904
1099
|
const fillDefaults = (schema, data) => {
|
|
905
1100
|
const result = {};
|
|
906
1101
|
for (const key of Object.keys(schema)) result[key] = data[key] !== void 0 ? data[key] : schema[key].default;
|
|
907
1102
|
return Object.freeze(result);
|
|
908
1103
|
};
|
|
1104
|
+
const typeFor = (value) => typeof value === "string" || typeof value === "number" || typeof value === "boolean" ? { type: typeof value } : {};
|
|
1105
|
+
const describeFromPropSchema = (input) => {
|
|
1106
|
+
const rich = new Set(input.richTextFields ?? []);
|
|
1107
|
+
const entries = Object.entries(input.propSchema);
|
|
1108
|
+
return {
|
|
1109
|
+
summary: `${input.title ?? input.type} block`,
|
|
1110
|
+
data: {
|
|
1111
|
+
type: "object",
|
|
1112
|
+
additionalProperties: false,
|
|
1113
|
+
properties: Object.fromEntries(entries.map(([key, entry]) => [key, rich.has(key) ? richText(`Rich-text field "${key}".`) : {
|
|
1114
|
+
...typeFor(entry.default),
|
|
1115
|
+
...entry.values === void 0 ? {} : { enum: [...entry.values] }
|
|
1116
|
+
}]))
|
|
1117
|
+
},
|
|
1118
|
+
defaultData: Object.fromEntries(entries.map(([key, entry]) => [key, entry.default]))
|
|
1119
|
+
};
|
|
1120
|
+
};
|
|
909
1121
|
const DATA_ATTR = {
|
|
910
1122
|
interface: "data-blok-interface",
|
|
911
1123
|
element: "data-blok-element",
|
|
@@ -917,6 +1129,12 @@ const DATA_ATTR = {
|
|
|
917
1129
|
loading: "data-blok-loading",
|
|
918
1130
|
loadingSkeleton: "data-blok-loading-skeleton",
|
|
919
1131
|
skeletonBar: "data-blok-skeleton-bar",
|
|
1132
|
+
aiGap: "data-blok-ai-gap",
|
|
1133
|
+
aiReplaced: "data-blok-ai-replaced",
|
|
1134
|
+
aiConsumed: "data-blok-ai-consumed",
|
|
1135
|
+
aiRewriting: "data-blok-ai-rewriting",
|
|
1136
|
+
aiPreview: "data-blok-ai-preview",
|
|
1137
|
+
aiSlot: "data-blok-ai-slot",
|
|
920
1138
|
version: "data-blok-version",
|
|
921
1139
|
id: "data-blok-id",
|
|
922
1140
|
pageId: "data-blok-page-id",
|
|
@@ -939,12 +1157,18 @@ const DATA_ATTR = {
|
|
|
939
1157
|
readonly: "data-blok-readonly",
|
|
940
1158
|
controlsHidden: "data-blok-controls-hidden",
|
|
941
1159
|
toolbarHidden: "data-blok-toolbar-hidden",
|
|
1160
|
+
noControls: "data-blok-no-controls",
|
|
942
1161
|
toolbarPosition: "data-blok-toolbar-position",
|
|
943
1162
|
contentAlign: "data-blok-content-align",
|
|
944
1163
|
rtl: "data-blok-rtl",
|
|
945
1164
|
width: "data-blok-width",
|
|
946
1165
|
nativeSelection: "data-blok-native-selection",
|
|
947
1166
|
crossSelection: "data-blok-cross-selection",
|
|
1167
|
+
pageHeader: "data-blok-page-header",
|
|
1168
|
+
pageTitle: "data-blok-page-title",
|
|
1169
|
+
pageIconRow: "data-blok-page-icon-row",
|
|
1170
|
+
pageIcon: "data-blok-page-icon",
|
|
1171
|
+
pageAddIcon: "data-blok-page-add-icon",
|
|
948
1172
|
dragging: "data-blok-dragging",
|
|
949
1173
|
draggingMulti: "data-blok-dragging-multi",
|
|
950
1174
|
duplicating: "data-blok-duplicating",
|
|
@@ -979,8 +1203,14 @@ const DATA_ATTR = {
|
|
|
979
1203
|
popoverItem: "data-blok-popover-item",
|
|
980
1204
|
popoverItemIcon: "data-blok-popover-item-icon",
|
|
981
1205
|
popoverItemIconChevronRight: "data-blok-popover-item-icon-chevron-right",
|
|
1206
|
+
popoverItemMore: "data-blok-popover-item-more",
|
|
982
1207
|
popoverItemTitle: "data-blok-popover-item-title",
|
|
983
1208
|
popoverItemSecondaryTitle: "data-blok-popover-item-secondary-title",
|
|
1209
|
+
popoverItemValue: "data-blok-popover-item-value",
|
|
1210
|
+
popoverItemDropdownButton: "data-blok-popover-item-dropdown-button",
|
|
1211
|
+
popoverCover: "data-blok-popover-cover",
|
|
1212
|
+
popoverItemDescription: "data-blok-popover-item-description",
|
|
1213
|
+
popoverItemSearchSuffix: "data-blok-popover-item-search-suffix",
|
|
984
1214
|
popoverItemActive: "data-blok-popover-item-active",
|
|
985
1215
|
popoverItemChildrenOpen: "data-blok-popover-item-children-open",
|
|
986
1216
|
popoverItemConfirmation: "data-blok-popover-item-confirmation",
|
|
@@ -1015,8 +1245,11 @@ const DATA_ATTR = {
|
|
|
1015
1245
|
childStandIn: "data-blok-child-stand-in",
|
|
1016
1246
|
mutationFree: "data-blok-mutation-free",
|
|
1017
1247
|
chrome: "data-blok-chrome",
|
|
1248
|
+
annotation: "data-blok-annotation",
|
|
1018
1249
|
keyboardOwner: "data-blok-keyboard-owner",
|
|
1250
|
+
contextMenuOwner: "data-blok-context-menu-owner",
|
|
1019
1251
|
linkOwner: "data-blok-link-owner",
|
|
1252
|
+
selectionOwner: "data-blok-selection-owner",
|
|
1020
1253
|
navigationFocused: "data-blok-navigation-focused",
|
|
1021
1254
|
flipperNavigationTarget: "data-blok-flipper-navigation-target",
|
|
1022
1255
|
inlineToolbar: "data-blok-inline-toolbar",
|
|
@@ -1352,6 +1585,17 @@ var BlokEditorComponent = class BlokEditorComponent {
|
|
|
1352
1585
|
cfg.onBeforeRender = handlers.onBeforeRender;
|
|
1353
1586
|
cfg.onAfterRender = handlers.onAfterRender;
|
|
1354
1587
|
this.appliedHandlers = handlers;
|
|
1588
|
+
if (cfg.pageTitle) cfg.pageTitle = {
|
|
1589
|
+
...typeof cfg.pageTitle === "object" ? cfg.pageTitle : {},
|
|
1590
|
+
onChange: (...args) => {
|
|
1591
|
+
const latest = this.escapeHatchConfig().pageTitle;
|
|
1592
|
+
if (latest !== null && typeof latest === "object" && latest.onChange !== void 0) this.ngZone.run(() => latest.onChange?.(...args));
|
|
1593
|
+
},
|
|
1594
|
+
onIconChange: (...args) => {
|
|
1595
|
+
const latest = this.escapeHatchConfig().pageTitle;
|
|
1596
|
+
if (latest !== null && typeof latest === "object" && latest.onIconChange !== void 0) this.ngZone.run(() => latest.onIconChange?.(...args));
|
|
1597
|
+
}
|
|
1598
|
+
};
|
|
1355
1599
|
if (this.themeChange.observed) cfg.onThemeChange = (resolved) => this.ngZone.run(() => this.themeChange.emit(resolved));
|
|
1356
1600
|
const beforePaste = this.onBeforePaste;
|
|
1357
1601
|
if (beforePaste !== void 0) cfg.onBeforePaste = (html) => beforePaste(html);
|
|
@@ -1568,7 +1812,7 @@ var BlokEditorComponent = class BlokEditorComponent {
|
|
|
1568
1812
|
}
|
|
1569
1813
|
static ɵfac = i0.ɵɵngDeclareFactory({
|
|
1570
1814
|
minVersion: "12.0.0",
|
|
1571
|
-
version: "22.2.
|
|
1815
|
+
version: "22.2.4",
|
|
1572
1816
|
ngImport: i0,
|
|
1573
1817
|
type: BlokEditorComponent,
|
|
1574
1818
|
deps: [],
|
|
@@ -1576,7 +1820,7 @@ var BlokEditorComponent = class BlokEditorComponent {
|
|
|
1576
1820
|
});
|
|
1577
1821
|
static ɵcmp = i0.ɵɵngDeclareComponent({
|
|
1578
1822
|
minVersion: "14.0.0",
|
|
1579
|
-
version: "22.2.
|
|
1823
|
+
version: "22.2.4",
|
|
1580
1824
|
type: BlokEditorComponent,
|
|
1581
1825
|
isStandalone: true,
|
|
1582
1826
|
selector: "blok-editor",
|
|
@@ -1638,7 +1882,7 @@ var BlokEditorComponent = class BlokEditorComponent {
|
|
|
1638
1882
|
};
|
|
1639
1883
|
i0.ɵɵngDeclareClassMetadata({
|
|
1640
1884
|
minVersion: "12.0.0",
|
|
1641
|
-
version: "22.2.
|
|
1885
|
+
version: "22.2.4",
|
|
1642
1886
|
ngImport: i0,
|
|
1643
1887
|
type: BlokEditorComponent,
|
|
1644
1888
|
decorators: [{
|
|
@@ -1692,6 +1936,60 @@ i0.ɵɵngDeclareClassMetadata({
|
|
|
1692
1936
|
recreateKey: [{ type: Input }]
|
|
1693
1937
|
}
|
|
1694
1938
|
});
|
|
1939
|
+
var BlokTitleComponent = class BlokTitleComponent {
|
|
1940
|
+
host = inject(ElementRef).nativeElement;
|
|
1941
|
+
editor = null;
|
|
1942
|
+
ngOnChanges(changes) {
|
|
1943
|
+
const change = changes["editor"];
|
|
1944
|
+
if (change === void 0) return;
|
|
1945
|
+
release(change.previousValue);
|
|
1946
|
+
this.editor?.title.mount(this.host);
|
|
1947
|
+
}
|
|
1948
|
+
ngOnDestroy() {
|
|
1949
|
+
release(this.editor);
|
|
1950
|
+
}
|
|
1951
|
+
static ɵfac = i0.ɵɵngDeclareFactory({
|
|
1952
|
+
minVersion: "12.0.0",
|
|
1953
|
+
version: "22.2.4",
|
|
1954
|
+
ngImport: i0,
|
|
1955
|
+
type: BlokTitleComponent,
|
|
1956
|
+
deps: [],
|
|
1957
|
+
target: i0.ɵɵFactoryTarget.Component
|
|
1958
|
+
});
|
|
1959
|
+
static ɵcmp = i0.ɵɵngDeclareComponent({
|
|
1960
|
+
minVersion: "14.0.0",
|
|
1961
|
+
version: "22.2.4",
|
|
1962
|
+
type: BlokTitleComponent,
|
|
1963
|
+
isStandalone: true,
|
|
1964
|
+
selector: "blok-title",
|
|
1965
|
+
inputs: { editor: "editor" },
|
|
1966
|
+
usesOnChanges: true,
|
|
1967
|
+
ngImport: i0,
|
|
1968
|
+
template: "",
|
|
1969
|
+
isInline: true,
|
|
1970
|
+
changeDetection: i0.ChangeDetectionStrategy.OnPush
|
|
1971
|
+
});
|
|
1972
|
+
};
|
|
1973
|
+
i0.ɵɵngDeclareClassMetadata({
|
|
1974
|
+
minVersion: "12.0.0",
|
|
1975
|
+
version: "22.2.4",
|
|
1976
|
+
ngImport: i0,
|
|
1977
|
+
type: BlokTitleComponent,
|
|
1978
|
+
decorators: [{
|
|
1979
|
+
type: Component,
|
|
1980
|
+
args: [{
|
|
1981
|
+
selector: "blok-title",
|
|
1982
|
+
standalone: true,
|
|
1983
|
+
changeDetection: ChangeDetectionStrategy.OnPush,
|
|
1984
|
+
template: ""
|
|
1985
|
+
}]
|
|
1986
|
+
}],
|
|
1987
|
+
propDecorators: { editor: [{ type: Input }] }
|
|
1988
|
+
});
|
|
1989
|
+
const release = (editor) => {
|
|
1990
|
+
const title = editor?.title;
|
|
1991
|
+
if (typeof title?.mount === "function") title.mount(null);
|
|
1992
|
+
};
|
|
1695
1993
|
const RESERVED_STATICS = [
|
|
1696
1994
|
"toolbox",
|
|
1697
1995
|
"isReadOnlySupported",
|
|
@@ -1808,15 +2106,21 @@ function createAngularBlock(spec) {
|
|
|
1808
2106
|
onNavigationEnter(event) {
|
|
1809
2107
|
return spec.onNavigationEnter?.(event, this.blockApi) === true;
|
|
1810
2108
|
}
|
|
2109
|
+
isReadOnly() {
|
|
2110
|
+
return spec.isReadOnly?.(this.blockApi) === true;
|
|
2111
|
+
}
|
|
2112
|
+
isDataReadOnly() {
|
|
2113
|
+
return spec.isDataReadOnly?.(this.blockApi) === true;
|
|
2114
|
+
}
|
|
1811
2115
|
setToolbarAnchor = (element) => {
|
|
1812
2116
|
this.anchorEl = element;
|
|
1813
2117
|
};
|
|
1814
2118
|
moved() {
|
|
1815
2119
|
spec.onMoved?.(this.blockApi);
|
|
1816
2120
|
}
|
|
1817
|
-
removed() {
|
|
2121
|
+
removed(removal) {
|
|
1818
2122
|
this.registry?.unregister(this.blockApi.id, this.hostEl ?? void 0);
|
|
1819
|
-
spec.onRemoved?.(this.blockApi);
|
|
2123
|
+
spec.onRemoved?.(this.blockApi, removal);
|
|
1820
2124
|
}
|
|
1821
2125
|
destroy() {
|
|
1822
2126
|
this.registry?.unregister(this.blockApi.id, this.hostEl ?? void 0);
|
|
@@ -1879,6 +2183,17 @@ function createAngularBlock(spec) {
|
|
|
1879
2183
|
configurable: true
|
|
1880
2184
|
});
|
|
1881
2185
|
}
|
|
2186
|
+
if (spec.statics?.describe === void 0) Object.defineProperty(AngularBlockTool, "describe", {
|
|
2187
|
+
value: () => describeFromPropSchema({
|
|
2188
|
+
type: spec.type,
|
|
2189
|
+
title: spec.toolbox !== void 0 && !Array.isArray(spec.toolbox) ? spec.toolbox.title : void 0,
|
|
2190
|
+
propSchema: spec.propSchema,
|
|
2191
|
+
richTextFields: spec.statics?.richTextFields
|
|
2192
|
+
}),
|
|
2193
|
+
writable: true,
|
|
2194
|
+
enumerable: true,
|
|
2195
|
+
configurable: true
|
|
2196
|
+
});
|
|
1882
2197
|
return AngularBlockTool;
|
|
1883
2198
|
}
|
|
1884
2199
|
const BLOCK_CHANGED_EVENT = "block changed";
|
|
@@ -1928,7 +2243,7 @@ function injectBlocks(editor, options = {}) {
|
|
|
1928
2243
|
insertMany: (specs) => bound().insertMany(specs),
|
|
1929
2244
|
insertTree: (spec) => bound().insertTree(spec),
|
|
1930
2245
|
insertMarkdown: (markdown, options) => bound().insertMarkdown(markdown, options),
|
|
1931
|
-
exportMarkdown: () => bound().exportMarkdown(),
|
|
2246
|
+
exportMarkdown: (options) => bound().exportMarkdown(options),
|
|
1932
2247
|
move: (id, target) => bound().move(id, target),
|
|
1933
2248
|
nest: (id, parentId) => bound().nest(id, parentId),
|
|
1934
2249
|
unnest: (id) => bound().unnest(id),
|
|
@@ -1948,6 +2263,7 @@ function injectBlocks(editor, options = {}) {
|
|
|
1948
2263
|
insertOutputData: (blocks, options) => bound().insertOutputData(blocks, options),
|
|
1949
2264
|
splitBlock: (currentBlockId, currentBlockData, newBlockType, newBlockData, insertIndex) => bound().splitBlock(currentBlockId, currentBlockData, newBlockType, newBlockData, insertIndex),
|
|
1950
2265
|
insertInsideParent: (parentId, insertIndex, childData) => bound().insertInsideParent(parentId, insertIndex, childData),
|
|
2266
|
+
create: (spec) => bound().create(spec),
|
|
1951
2267
|
render: (data) => bound().render(data),
|
|
1952
2268
|
clear: () => bound().clear(),
|
|
1953
2269
|
isSyncingFromYjs: () => bound().isSyncingFromYjs()
|
|
@@ -1972,6 +2288,5 @@ function injectBlokReady(options = {}) {
|
|
|
1972
2288
|
afterNextRender(read);
|
|
1973
2289
|
return ready.asReadonly();
|
|
1974
2290
|
}
|
|
1975
|
-
export { BLOK_BLOCK_CONTEXT, BLOK_DEFAULT_CONFIG, BLOK_EDITOR_INSTANCE, BlokContentDirective, BlokEditorComponent, createAngularBlock, injectBlocks, injectBlokInstance, injectBlokReady, provideBlok };
|
|
2291
|
+
export { BLOK_BLOCK_CONTEXT, BLOK_DEFAULT_CONFIG, BLOK_EDITOR_INSTANCE, BlokContentDirective, BlokEditorComponent, BlokTitleComponent, createAngularBlock, injectBlocks, injectBlokInstance, injectBlokReady, provideBlok };
|
|
1976
2292
|
|
|
1977
|
-
//# sourceMappingURL=bloklabs-angular.mjs.map
|
package/package.json
CHANGED
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
{
|
|
2
2
|
"name": "@bloklabs/angular",
|
|
3
|
-
"version": "1.
|
|
3
|
+
"version": "2.1.0",
|
|
4
4
|
"description": "Angular block editor — official Angular bindings for Blok, the headless Notion-like rich text editor. Standalone components that render blocks and save to JSON (APF partial-Ivy bundle).",
|
|
5
5
|
"license": "Apache-2.0",
|
|
6
6
|
"author": "JackUait",
|
|
@@ -36,7 +36,7 @@
|
|
|
36
36
|
"@angular/common": ">=20 <23",
|
|
37
37
|
"@angular/core": ">=20 <23",
|
|
38
38
|
"@angular/forms": ">=20 <23",
|
|
39
|
-
"@bloklabs/core": "1.
|
|
39
|
+
"@bloklabs/core": "2.1.0"
|
|
40
40
|
},
|
|
41
41
|
"module": "fesm2022/bloklabs-angular.mjs",
|
|
42
42
|
"typings": "./index.d.ts",
|