@lblod/ember-rdfa-editor 13.2.1 → 13.3.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.
Files changed (43) hide show
  1. package/declarations/components/ember-node/embedded-editor.d.ts +14 -34
  2. package/declarations/components/ember-node/inline-rdfa.d.ts +2 -2
  3. package/declarations/components/ember-node/link.d.ts +18 -12
  4. package/declarations/components/pill.d.ts +15 -7
  5. package/declarations/components/plugins/link/_private/link-editor.d.ts +37 -0
  6. package/declarations/components/plugins/link/link-editor.d.ts +6 -20
  7. package/declarations/components/plugins/link/link-menu.d.ts +3 -0
  8. package/declarations/components/plugins/link/link-sidebar-widget.d.ts +16 -0
  9. package/declarations/plugins/link/input-rule.d.ts +19 -0
  10. package/declarations/plugins/link/nodes/link.d.ts +2 -0
  11. package/declarations/plugins/link/parser.d.ts +17 -0
  12. package/dist/_app_/components/plugins/link/_private/link-editor.js +1 -0
  13. package/dist/_app_/components/plugins/link/link-sidebar-widget.js +1 -0
  14. package/dist/components/ember-node/embedded-editor.js +13 -29
  15. package/dist/components/ember-node/embedded-editor.js.map +1 -1
  16. package/dist/components/ember-node/inline-rdfa.js +12 -4
  17. package/dist/components/ember-node/inline-rdfa.js.map +1 -1
  18. package/dist/components/ember-node/link.js +86 -49
  19. package/dist/components/ember-node/link.js.map +1 -1
  20. package/dist/components/ember-node/slot.js +10 -4
  21. package/dist/components/ember-node/slot.js.map +1 -1
  22. package/dist/components/pill.js +12 -3
  23. package/dist/components/pill.js.map +1 -1
  24. package/dist/components/plugins/link/_private/link-editor.js +128 -0
  25. package/dist/components/plugins/link/_private/link-editor.js.map +1 -0
  26. package/dist/components/plugins/link/link-editor.js +5 -78
  27. package/dist/components/plugins/link/link-editor.js.map +1 -1
  28. package/dist/components/plugins/link/link-menu.js +25 -8
  29. package/dist/components/plugins/link/link-menu.js.map +1 -1
  30. package/dist/components/plugins/link/link-sidebar-widget.js +40 -0
  31. package/dist/components/plugins/link/link-sidebar-widget.js.map +1 -0
  32. package/dist/nodes/inline-rdfa.js.map +1 -1
  33. package/dist/plugins/link/input-rule.js +82 -0
  34. package/dist/plugins/link/input-rule.js.map +1 -0
  35. package/dist/plugins/link/nodes/link.js +11 -1
  36. package/dist/plugins/link/nodes/link.js.map +1 -1
  37. package/dist/plugins/link/parser.js +58 -0
  38. package/dist/plugins/link/parser.js.map +1 -0
  39. package/package.json +4 -1
  40. package/scss/_c-formatting-marks.scss +0 -1
  41. package/scss/_c-link.scss +27 -27
  42. package/scss/_c-table.scss +4 -0
  43. package/vendor/ember-rdfa-editor.css +26 -25
@@ -1,19 +1,24 @@
1
1
  import { action } from '@ember/object';
2
2
  import Component from '@glimmer/component';
3
3
  import { wrapSelection } from '../../../commands/wrap-selection.js';
4
- import { linkToHref } from '../../../utils/_private/string-utils.js';
5
4
  import { LinkIcon } from '@appuniversum/ember-appuniversum/components/icons/link';
5
+ import ToolbarButton from '../../toolbar/button.js';
6
+ import t from 'ember-intl/helpers/t';
7
+ import { on } from '@ember/modifier';
8
+ import { not } from 'ember-truth-helpers';
9
+ import { defaultLinkParser } from '../../../plugins/link/parser.js';
6
10
  import { precompileTemplate } from '@ember/template-compilation';
7
- import { n } from 'decorator-transforms/runtime';
8
11
  import { setComponentTemplate } from '@ember/component';
9
-
10
- var TEMPLATE = precompileTemplate("{{! @glint-nocheck: not typesafe yet }}\n{{#if @controller}}\n <Toolbar::Button\n @title={{t \"ember-rdfa-editor.link.insert\"}}\n @icon={{this.LinkIcon}}\n {{on \"click\" this.insert}}\n @disabled={{not this.canInsert}}\n />\n{{/if}}");
12
+ import { n } from 'decorator-transforms/runtime';
11
13
 
12
14
  class LinkMenu extends Component {
13
15
  LinkIcon = LinkIcon;
14
16
  get controller() {
15
17
  return this.args.controller;
16
18
  }
19
+ parseLink = input => {
20
+ return this.args.linkParser ? this.args.linkParser(input) : defaultLinkParser()(input);
21
+ };
17
22
  get schema() {
18
23
  return this.controller.schema;
19
24
  }
@@ -25,12 +30,14 @@ class LinkMenu extends Component {
25
30
  this.controller.doCommand(wrapSelection(this.schema.nodes['link'], nodeRange => {
26
31
  if (nodeRange) {
27
32
  const text = nodeRange.$from.doc.textBetween(nodeRange.$from.pos, nodeRange.$to.pos);
28
- const href = linkToHref(text);
33
+ const linkParserResult = this.parseLink(text);
29
34
  return {
30
- href
35
+ href: linkParserResult.value ?? text
31
36
  };
32
37
  } else {
33
- return null;
38
+ return {
39
+ isNew: true
40
+ };
34
41
  }
35
42
  }));
36
43
  this.controller.focus();
@@ -40,8 +47,18 @@ class LinkMenu extends Component {
40
47
  static {
41
48
  n(this.prototype, "insert", [action]);
42
49
  }
50
+ static {
51
+ setComponentTemplate(precompileTemplate("\n {{#if @controller}}\n <ToolbarButton @title={{t \"ember-rdfa-editor.link.insert\"}} @icon={{this.LinkIcon}} {{on \"click\" this.insert}} @disabled={{not this.canInsert}} />\n {{/if}}\n ", {
52
+ strictMode: true,
53
+ scope: () => ({
54
+ ToolbarButton,
55
+ t,
56
+ not,
57
+ on
58
+ })
59
+ }), this);
60
+ }
43
61
  }
44
- setComponentTemplate(TEMPLATE, LinkMenu);
45
62
 
46
63
  export { LinkMenu as default };
47
64
  //# sourceMappingURL=link-menu.js.map
@@ -1 +1 @@
1
- {"version":3,"file":"link-menu.js","sources":["../../../../src/components/plugins/link/link-menu.ts"],"sourcesContent":["import { action } from '@ember/object';\nimport Component from '@glimmer/component';\nimport { wrapSelection } from '#root/commands/wrap-selection.ts';\nimport { linkToHref } from '#root/utils/_private/string-utils.ts';\nimport { LinkIcon } from '@appuniversum/ember-appuniversum/components/icons/link';\nimport type SayController from '#root/core/say-controller.ts';\n\ntype Args = {\n controller: SayController;\n onActivate?: () => void;\n};\nexport default class LinkMenu extends Component<Args> {\n LinkIcon = LinkIcon;\n\n get controller() {\n return this.args.controller;\n }\n\n get schema() {\n return this.controller.schema;\n }\n\n get canInsert() {\n return (\n !this.controller.inEmbeddedView &&\n this.controller.checkCommand(wrapSelection(this.schema.nodes['link']))\n );\n }\n\n @action\n insert() {\n if (!this.controller.inEmbeddedView) {\n this.controller.doCommand(\n wrapSelection(this.schema.nodes['link'], (nodeRange) => {\n if (nodeRange) {\n const text = nodeRange.$from.doc.textBetween(\n nodeRange.$from.pos,\n nodeRange.$to.pos,\n );\n const href = linkToHref(text);\n return { href };\n } else {\n return null;\n }\n }),\n );\n this.controller.focus();\n this.args.onActivate?.();\n }\n }\n}\n"],"names":["LinkMenu","Component","LinkIcon","controller","args","schema","canInsert","inEmbeddedView","checkCommand","wrapSelection","nodes","insert","doCommand","nodeRange","text","$from","doc","textBetween","pos","$to","href","linkToHref","focus","onActivate","n","prototype","action","setComponentTemplate","TEMPLATE"],"mappings":";;;;;;;;;;;AAWe,MAAMA,QAAQ,SAASC,SAAS,CAAO;AACpDC,EAAAA,QAAQ,GAAGA,QAAQ;EAEnB,IAAIC,UAAUA,GAAG;AACf,IAAA,OAAO,IAAI,CAACC,IAAI,CAACD,UAAU;AAC7B,EAAA;EAEA,IAAIE,MAAMA,GAAG;AACX,IAAA,OAAO,IAAI,CAACF,UAAU,CAACE,MAAM;AAC/B,EAAA;EAEA,IAAIC,SAASA,GAAG;IACd,OACE,CAAC,IAAI,CAACH,UAAU,CAACI,cAAc,IAC/B,IAAI,CAACJ,UAAU,CAACK,YAAY,CAACC,aAAa,CAAC,IAAI,CAACJ,MAAM,CAACK,KAAK,CAAC,MAAM,CAAC,CAAC,CAAC;AAE1E,EAAA;AAGAC,EAAAA,MAAMA,GAAG;AACP,IAAA,IAAI,CAAC,IAAI,CAACR,UAAU,CAACI,cAAc,EAAE;AACnC,MAAA,IAAI,CAACJ,UAAU,CAACS,SAAS,CACvBH,aAAa,CAAC,IAAI,CAACJ,MAAM,CAACK,KAAK,CAAC,MAAM,CAAC,EAAGG,SAAS,IAAK;AACtD,QAAA,IAAIA,SAAS,EAAE;UACb,MAAMC,IAAI,GAAGD,SAAS,CAACE,KAAK,CAACC,GAAG,CAACC,WAAW,CAC1CJ,SAAS,CAACE,KAAK,CAACG,GAAG,EACnBL,SAAS,CAACM,GAAG,CAACD,GAChB,CAAC;AACD,UAAA,MAAME,IAAI,GAAGC,UAAU,CAACP,IAAI,CAAC;UAC7B,OAAO;AAAEM,YAAAA;WAAM;AACjB,QAAA,CAAC,MAAM;AACL,UAAA,OAAO,IAAI;AACb,QAAA;AACF,MAAA,CAAC,CACH,CAAC;AACD,MAAA,IAAI,CAACjB,UAAU,CAACmB,KAAK,EAAE;AACvB,MAAA,IAAI,CAAClB,IAAI,CAACmB,UAAU,IAAI;AAC1B,IAAA;AACF,EAAA;AAAC,EAAA;IAAAC,CAAA,CAAA,IAAA,CAAAC,SAAA,EAAA,QAAA,EAAA,CApBAC,MAAM,CAAA,CAAA;AAAA;AAqBT;AAACC,oBAAA,CAAAC,QAAA,EAvCoB5B,QAAQ,CAAA;;;;"}
1
+ {"version":3,"file":"link-menu.js","sources":["../../../../src/components/plugins/link/link-menu.gts"],"sourcesContent":["import { action } from '@ember/object';\nimport Component from '@glimmer/component';\nimport { wrapSelection } from '#root/commands/wrap-selection.ts';\nimport { LinkIcon } from '@appuniversum/ember-appuniversum/components/icons/link';\nimport type SayController from '#root/core/say-controller.ts';\nimport ToolbarButton from '#root/components/toolbar/button.gts';\nimport t from 'ember-intl/helpers/t';\nimport { on } from '@ember/modifier';\nimport { not } from 'ember-truth-helpers';\nimport {\n defaultLinkParser,\n type LinkParser,\n} from '#root/plugins/link/parser.ts';\n\ntype Args = {\n controller: SayController;\n onActivate?: () => void;\n linkParser?: LinkParser;\n};\nexport default class LinkMenu extends Component<Args> {\n LinkIcon = LinkIcon;\n\n get controller() {\n return this.args.controller;\n }\n\n parseLink: LinkParser = (input?: string) => {\n return this.args.linkParser\n ? this.args.linkParser(input)\n : defaultLinkParser()(input);\n };\n\n get schema() {\n return this.controller.schema;\n }\n\n get canInsert() {\n return (\n !this.controller.inEmbeddedView &&\n this.controller.checkCommand(wrapSelection(this.schema.nodes['link']))\n );\n }\n\n @action\n insert() {\n if (!this.controller.inEmbeddedView) {\n this.controller.doCommand(\n wrapSelection(this.schema.nodes['link'], (nodeRange) => {\n if (nodeRange) {\n const text = nodeRange.$from.doc.textBetween(\n nodeRange.$from.pos,\n nodeRange.$to.pos,\n );\n const linkParserResult = this.parseLink(text);\n return { href: linkParserResult.value ?? text };\n } else {\n return { isNew: true };\n }\n }),\n );\n this.controller.focus();\n this.args.onActivate?.();\n }\n }\n\n <template>\n {{#if @controller}}\n <ToolbarButton\n @title={{t \"ember-rdfa-editor.link.insert\"}}\n @icon={{this.LinkIcon}}\n {{on \"click\" this.insert}}\n @disabled={{not this.canInsert}}\n />\n {{/if}}\n </template>\n}\n"],"names":["LinkMenu","Component","LinkIcon","controller","args","parseLink","input","linkParser","defaultLinkParser","schema","canInsert","inEmbeddedView","checkCommand","wrapSelection","nodes","insert","doCommand","nodeRange","text","$from","doc","textBetween","pos","$to","linkParserResult","href","value","isNew","focus","onActivate","n","prototype","action","setComponentTemplate","precompileTemplate","strictMode","scope","ToolbarButton","t","not","on"],"mappings":";;;;;;;;;;;;;AAmBe,MAAMA,iBAAiBC,SAAA,CAAU;AAC9CC,EAAAA,QAAA,GAAWA,QAAA;EAEX,IAAIC,UAAAA,GAAa;AACf,IAAA,OAAO,IAAI,CAACC,IAAI,CAACD,UAAU;AAC7B,EAAA;EAEAE,SAAA,GAAyBC,KAAc,IAAA;IACrC,OAAO,IAAI,CAACF,IAAI,CAACG,UAAU,GACvB,IAAI,CAACH,IAAI,CAACG,UAAU,CAACD,SACrBE,iBAAA,EAAA,CAAoBF,KAAA,CAAA;EAC1B,CAAA;EAEA,IAAIG,MAAAA,GAAS;AACX,IAAA,OAAO,IAAI,CAACN,UAAU,CAACM,MAAM;AAC/B,EAAA;EAEA,IAAIC,SAAAA,GAAY;IACd,OACE,CAAC,IAAI,CAACP,UAAU,CAACQ,cAAc,IAC/B,IAAI,CAACR,UAAU,CAACS,YAAY,CAACC,cAAc,IAAI,CAACJ,MAAM,CAACK,KAAK,CAAC,MAAA,CAAO,CAAA,CACtE;AACF,EAAA;AAGAC,EAAAA,MAAAA,GAAS;AACP,IAAA,IAAI,CAAC,IAAI,CAACZ,UAAU,CAACQ,cAAc,EAAE;AACnC,MAAA,IAAI,CAACR,UAAU,CAACa,SAAS,CACvBH,aAAA,CAAc,IAAI,CAACJ,MAAM,CAACK,KAAK,CAAC,MAAA,CAAO,EAAGG,SAAA,IAAA;AACxC,QAAA,IAAIA,SAAA,EAAW;UACb,MAAMC,OAAOD,SAAA,CAAUE,KAAK,CAACC,GAAG,CAACC,WAAW,CAC1CJ,SAAA,CAAUE,KAAK,CAACG,GAAG,EACnBL,SAAA,CAAUM,GAAG,CAACD,GAAG,CAAA;AAEnB,UAAA,MAAME,gBAAA,GAAmB,IAAI,CAACnB,SAAS,CAACa,IAAA,CAAA;UACxC,OAAO;AAAEO,YAAAA,IAAA,EAAMD,gBAAA,CAAiBE,KAAK,IAAIR;WAAK;AAChD,QAAA,CAAA,MAAO;UACL,OAAO;AAAES,YAAAA,KAAA,EAAO;WAAK;AACvB,QAAA;AACF,MAAA,CAAA,CAAA,CAAA;AAEF,MAAA,IAAI,CAACxB,UAAU,CAACyB,KAAK,EAAA;AACrB,MAAA,IAAI,CAACxB,IAAI,CAACyB,UAAU,IAAA;AACtB,IAAA;AACF,EAAA;AAAA,EAAA;IAAAC,CAAA,CAAA,IAAA,CAAAC,SAAA,EAAA,QAAA,EAAA,CApBCC,MAAA,CAAA,CAAA;AAAA;AAsBD,EAAA;IAAAC,oBAAA,CAAAC,kBAAA,CAAA,0MAAA,EASA;MAAAC,UAAA,EAAA,IAAA;AAAAC,MAAAA,KAAA,EAAAA,OAAA;QAAAC,aAAA;QAAAC,CAAA;QAAAC,GAAA;AAAAC,QAAAA;AAAA,OAAA;KAAU,CAAA,EAAV,IAAW,CAAA;AAAD;AACZ;;;;"}
@@ -0,0 +1,40 @@
1
+ import Component from '@glimmer/component';
2
+ import { NodeSelection } from 'prosemirror-state';
3
+ import { defaultLinkParser } from '../../../plugins/link/parser.js';
4
+ import LinkEditor from './_private/link-editor.js';
5
+ import { precompileTemplate } from '@ember/template-compilation';
6
+ import { setComponentTemplate } from '@ember/component';
7
+
8
+ class LinkSidebarWidget extends Component {
9
+ get linkParser() {
10
+ return this.args.linkParser ?? defaultLinkParser();
11
+ }
12
+ get controller() {
13
+ return this.args.controller;
14
+ }
15
+ get link() {
16
+ if (this.controller) {
17
+ const {
18
+ selection
19
+ } = this.controller.mainEditorState;
20
+ if (selection instanceof NodeSelection && selection.node.type === this.controller.schema.nodes['link']) {
21
+ return {
22
+ pos: selection.from,
23
+ node: selection.node
24
+ };
25
+ }
26
+ }
27
+ return;
28
+ }
29
+ static {
30
+ setComponentTemplate(precompileTemplate("\n {{#if this.controller}}\n {{#if this.link}}\n <LinkEditor @link={{this.link}} @linkParser={{this.linkParser}} @controller={{this.controller}} @showTitle={{true}} />\n {{/if}}\n {{/if}}\n ", {
31
+ strictMode: true,
32
+ scope: () => ({
33
+ LinkEditor
34
+ })
35
+ }), this);
36
+ }
37
+ }
38
+
39
+ export { LinkSidebarWidget as default };
40
+ //# sourceMappingURL=link-sidebar-widget.js.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"link-sidebar-widget.js","sources":["../../../../src/components/plugins/link/link-sidebar-widget.gts"],"sourcesContent":["import Component from '@glimmer/component';\nimport { NodeSelection } from 'prosemirror-state';\nimport type SayController from '#root/core/say-controller.ts';\nimport type { LinkParser } from '#root/plugins/link/parser.js';\nimport { defaultLinkParser } from '#root/plugins/link/parser.ts';\nimport LinkEditor from './_private/link-editor.gts';\n\ntype Args = {\n controller?: SayController;\n linkParser?: LinkParser;\n};\n\nexport default class LinkSidebarWidget extends Component<Args> {\n get linkParser() {\n return this.args.linkParser ?? defaultLinkParser();\n }\n\n get controller() {\n return this.args.controller;\n }\n\n get link() {\n if (this.controller) {\n const { selection } = this.controller.mainEditorState;\n if (\n selection instanceof NodeSelection &&\n selection.node.type === this.controller.schema.nodes['link']\n ) {\n return { pos: selection.from, node: selection.node };\n }\n }\n return;\n }\n\n <template>\n {{#if this.controller}}\n {{#if this.link}}\n <LinkEditor\n @link={{this.link}}\n @linkParser={{this.linkParser}}\n @controller={{this.controller}}\n @showTitle={{true}}\n />\n {{/if}}\n {{/if}}\n </template>\n}\n"],"names":["LinkSidebarWidget","Component","linkParser","args","defaultLinkParser","controller","link","selection","mainEditorState","NodeSelection","node","type","schema","nodes","pos","from","setComponentTemplate","precompileTemplate","strictMode","scope","LinkEditor"],"mappings":";;;;;;;AAYe,MAAMA,0BAA0BC,SAAA,CAAU;EACvD,IAAIC,UAAAA,GAAa;IACf,OAAO,IAAI,CAACC,IAAI,CAACD,UAAU,IAAIE,iBAAA,EAAA;AACjC,EAAA;EAEA,IAAIC,UAAAA,GAAa;AACf,IAAA,OAAO,IAAI,CAACF,IAAI,CAACE,UAAU;AAC7B,EAAA;EAEA,IAAIC,IAAAA,GAAO;IACT,IAAI,IAAI,CAACD,UAAU,EAAE;MACnB,MAAM;AAAEE,QAAAA;AAAS,OAAE,GAAG,IAAI,CAACF,UAAU,CAACG,eAAe;MACrD,IACED,qBAAqBE,aAAA,IACrBF,SAAA,CAAUG,IAAI,CAACC,IAAI,KAAK,IAAI,CAACN,UAAU,CAACO,MAAM,CAACC,KAAK,CAAC,OAAO,EAC5D;QACA,OAAO;UAAEC,GAAA,EAAKP,UAAUQ,IAAI;UAAEL,IAAA,EAAMH,UAAUG;SAAK;AACrD,MAAA;AACF,IAAA;AACA,IAAA;AACF,EAAA;AAEA,EAAA;IAAAM,oBAAA,CAAAC,kBAAA,CAAA,wNAAA,EAWA;MAAAC,UAAA,EAAA,IAAA;AAAAC,MAAAA,KAAA,EAAAA,OAAA;AAAAC,QAAAA;AAAA,OAAA;KAAU,CAAA,EAAV,IAAW,CAAA;AAAD;AACZ;;;;"}
@@ -1 +1 @@
1
- {"version":3,"file":"inline-rdfa.js","sources":["../../src/nodes/inline-rdfa.ts"],"sourcesContent":["import { Node as PNode } from 'prosemirror-model';\nimport {\n getRdfaAttrs,\n getRdfaContentElement,\n rdfaAttrSpec,\n renderRdfaAware,\n} from '../core/schema.ts';\nimport {\n type EmberNodeConfig,\n createEmberNodeSpec,\n createEmberNodeView,\n} from '../utils/ember-node.ts';\nimport InlineRdfaComponent from '../components/ember-node/inline-rdfa.ts';\nimport type { ComponentLike } from '@glint/template';\nimport getClassnamesFromNode from '../utils/get-classnames-from-node.ts';\nimport type {\n ModelMigrationGenerator,\n RdfaAttrs,\n} from '#root/core/rdfa-types.ts';\n\ntype Options = {\n rdfaAware?: boolean;\n /**\n * Migrations to apply to nodes parsed as inline-rdfa, to modify the data model.\n * @returns false to use the default parsing or an object to define overrides\n **/\n modelMigrations?: ModelMigrationGenerator[];\n};\n\nconst emberNodeConfig: (options?: Options) => EmberNodeConfig = ({\n rdfaAware = false,\n modelMigrations = [],\n} = {}) => {\n return {\n name: 'inline-rdfa',\n inline: true,\n component: InlineRdfaComponent as unknown as ComponentLike,\n group: 'inline',\n content: 'inline*',\n atom: true,\n draggable: false,\n selectable: true,\n editable: rdfaAware,\n isolating: rdfaAware,\n classNames: ['say-inline-rdfa'],\n toDOM(node: PNode) {\n if (rdfaAware) {\n return renderRdfaAware({\n renderable: node,\n tag: 'span',\n attrs: { class: getClassnamesFromNode(node) },\n content: 0,\n });\n } else {\n return [\n 'span',\n { ...node.attrs, class: getClassnamesFromNode(node) },\n 0,\n ];\n }\n },\n parseDOM: [\n {\n tag: 'span',\n // default prio is 50, highest prio comes first, and this parserule should at least come after all other nodes\n priority: 10,\n getAttrs(element: string | HTMLElement) {\n if (typeof element === 'string') {\n return false;\n }\n const attrs = getRdfaAttrs(element, { rdfaAware });\n if (attrs) {\n const migration = modelMigrations.find((migration) =>\n migration(attrs as unknown as RdfaAttrs),\n )?.(attrs as unknown as RdfaAttrs);\n if (migration && migration.getAttrs) {\n return migration.getAttrs(element);\n }\n return attrs;\n }\n return false;\n },\n contentElement: (element) => {\n if (rdfaAware && modelMigrations.length > 0) {\n const attrs = getRdfaAttrs(element, { rdfaAware });\n if (attrs) {\n const migration = modelMigrations.find((migration) =>\n migration(attrs as unknown as RdfaAttrs),\n )?.(attrs as unknown as RdfaAttrs);\n if (migration && migration.contentElement) {\n return migration.contentElement(element);\n }\n }\n }\n return getRdfaContentElement(element);\n },\n },\n ],\n attrs: rdfaAttrSpec({ rdfaAware }),\n };\n};\n\nexport const inlineRdfaWithConfig = (options?: Options) =>\n createEmberNodeSpec(emberNodeConfig(options));\n\nexport const inlineRdfaWithConfigView = (options?: Options) =>\n createEmberNodeView(emberNodeConfig(options));\n"],"names":["emberNodeConfig","rdfaAware","modelMigrations","name","inline","component","InlineRdfaComponent","group","content","atom","draggable","selectable","editable","isolating","classNames","toDOM","node","renderRdfaAware","renderable","tag","attrs","class","getClassnamesFromNode","parseDOM","priority","getAttrs","element","getRdfaAttrs","migration","find","contentElement","length","getRdfaContentElement","rdfaAttrSpec","inlineRdfaWithConfig","options","createEmberNodeSpec","inlineRdfaWithConfigView","createEmberNodeView"],"mappings":"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"}
1
+ {"version":3,"file":"inline-rdfa.js","sources":["../../src/nodes/inline-rdfa.ts"],"sourcesContent":["import { Node as PNode } from 'prosemirror-model';\nimport {\n getRdfaAttrs,\n getRdfaContentElement,\n rdfaAttrSpec,\n renderRdfaAware,\n} from '../core/schema.ts';\nimport {\n type EmberNodeConfig,\n createEmberNodeSpec,\n createEmberNodeView,\n} from '../utils/ember-node.ts';\nimport InlineRdfaComponent from '../components/ember-node/inline-rdfa.gts';\nimport type { ComponentLike } from '@glint/template';\nimport getClassnamesFromNode from '../utils/get-classnames-from-node.ts';\nimport type {\n ModelMigrationGenerator,\n RdfaAttrs,\n} from '#root/core/rdfa-types.ts';\n\ntype Options = {\n rdfaAware?: boolean;\n /**\n * Migrations to apply to nodes parsed as inline-rdfa, to modify the data model.\n * @returns false to use the default parsing or an object to define overrides\n **/\n modelMigrations?: ModelMigrationGenerator[];\n};\n\nconst emberNodeConfig: (options?: Options) => EmberNodeConfig = ({\n rdfaAware = false,\n modelMigrations = [],\n} = {}) => {\n return {\n name: 'inline-rdfa',\n inline: true,\n component: InlineRdfaComponent as unknown as ComponentLike,\n group: 'inline',\n content: 'inline*',\n atom: true,\n draggable: false,\n selectable: true,\n editable: rdfaAware,\n isolating: rdfaAware,\n classNames: ['say-inline-rdfa'],\n toDOM(node: PNode) {\n if (rdfaAware) {\n return renderRdfaAware({\n renderable: node,\n tag: 'span',\n attrs: { class: getClassnamesFromNode(node) },\n content: 0,\n });\n } else {\n return [\n 'span',\n { ...node.attrs, class: getClassnamesFromNode(node) },\n 0,\n ];\n }\n },\n parseDOM: [\n {\n tag: 'span',\n // default prio is 50, highest prio comes first, and this parserule should at least come after all other nodes\n priority: 10,\n getAttrs(element: string | HTMLElement) {\n if (typeof element === 'string') {\n return false;\n }\n const attrs = getRdfaAttrs(element, { rdfaAware });\n if (attrs) {\n const migration = modelMigrations.find((migration) =>\n migration(attrs as unknown as RdfaAttrs),\n )?.(attrs as unknown as RdfaAttrs);\n if (migration && migration.getAttrs) {\n return migration.getAttrs(element);\n }\n return attrs;\n }\n return false;\n },\n contentElement: (element) => {\n if (rdfaAware && modelMigrations.length > 0) {\n const attrs = getRdfaAttrs(element, { rdfaAware });\n if (attrs) {\n const migration = modelMigrations.find((migration) =>\n migration(attrs as unknown as RdfaAttrs),\n )?.(attrs as unknown as RdfaAttrs);\n if (migration && migration.contentElement) {\n return migration.contentElement(element);\n }\n }\n }\n return getRdfaContentElement(element);\n },\n },\n ],\n attrs: rdfaAttrSpec({ rdfaAware }),\n };\n};\n\nexport const inlineRdfaWithConfig = (options?: Options) =>\n createEmberNodeSpec(emberNodeConfig(options));\n\nexport const inlineRdfaWithConfigView = (options?: Options) =>\n createEmberNodeView(emberNodeConfig(options));\n"],"names":["emberNodeConfig","rdfaAware","modelMigrations","name","inline","component","InlineRdfaComponent","group","content","atom","draggable","selectable","editable","isolating","classNames","toDOM","node","renderRdfaAware","renderable","tag","attrs","class","getClassnamesFromNode","parseDOM","priority","getAttrs","element","getRdfaAttrs","migration","find","contentElement","length","getRdfaContentElement","rdfaAttrSpec","inlineRdfaWithConfig","options","createEmberNodeSpec","inlineRdfaWithConfigView","createEmberNodeView"],"mappings":";;;;;;AA6BA,MAAMA,eAAuD,GAAGA,CAAC;AAC/DC,EAAAA,SAAS,GAAG,KAAK;AACjBC,EAAAA,eAAe,GAAG;AACpB,CAAC,GAAG,EAAE,KAAK;EACT,OAAO;AACLC,IAAAA,IAAI,EAAE,aAAa;AACnBC,IAAAA,MAAM,EAAE,IAAI;AACZC,IAAAA,SAAS,EAAEC,mBAA+C;AAC1DC,IAAAA,KAAK,EAAE,QAAQ;AACfC,IAAAA,OAAO,EAAE,SAAS;AAClBC,IAAAA,IAAI,EAAE,IAAI;AACVC,IAAAA,SAAS,EAAE,KAAK;AAChBC,IAAAA,UAAU,EAAE,IAAI;AAChBC,IAAAA,QAAQ,EAAEX,SAAS;AACnBY,IAAAA,SAAS,EAAEZ,SAAS;IACpBa,UAAU,EAAE,CAAC,iBAAiB,CAAC;IAC/BC,KAAKA,CAACC,IAAW,EAAE;AACjB,MAAA,IAAIf,SAAS,EAAE;AACb,QAAA,OAAOgB,eAAe,CAAC;AACrBC,UAAAA,UAAU,EAAEF,IAAI;AAChBG,UAAAA,GAAG,EAAE,MAAM;AACXC,UAAAA,KAAK,EAAE;YAAEC,KAAK,EAAEC,qBAAqB,CAACN,IAAI;WAAG;AAC7CR,UAAAA,OAAO,EAAE;AACX,SAAC,CAAC;AACJ,MAAA,CAAC,MAAM;QACL,OAAO,CACL,MAAM,EACN;UAAE,GAAGQ,IAAI,CAACI,KAAK;UAAEC,KAAK,EAAEC,qBAAqB,CAACN,IAAI;SAAG,EACrD,CAAC,CACF;AACH,MAAA;IACF,CAAC;AACDO,IAAAA,QAAQ,EAAE,CACR;AACEJ,MAAAA,GAAG,EAAE,MAAM;AACX;AACAK,MAAAA,QAAQ,EAAE,EAAE;MACZC,QAAQA,CAACC,OAA6B,EAAE;AACtC,QAAA,IAAI,OAAOA,OAAO,KAAK,QAAQ,EAAE;AAC/B,UAAA,OAAO,KAAK;AACd,QAAA;AACA,QAAA,MAAMN,KAAK,GAAGO,YAAY,CAACD,OAAO,EAAE;AAAEzB,UAAAA;AAAU,SAAC,CAAC;AAClD,QAAA,IAAImB,KAAK,EAAE;AACT,UAAA,MAAMQ,SAAS,GAAG1B,eAAe,CAAC2B,IAAI,CAAED,SAAS,IAC/CA,SAAS,CAACR,KAA6B,CACzC,CAAC,GAAGA,KAA6B,CAAC;AAClC,UAAA,IAAIQ,SAAS,IAAIA,SAAS,CAACH,QAAQ,EAAE;AACnC,YAAA,OAAOG,SAAS,CAACH,QAAQ,CAACC,OAAO,CAAC;AACpC,UAAA;AACA,UAAA,OAAON,KAAK;AACd,QAAA;AACA,QAAA,OAAO,KAAK;MACd,CAAC;MACDU,cAAc,EAAGJ,OAAO,IAAK;AAC3B,QAAA,IAAIzB,SAAS,IAAIC,eAAe,CAAC6B,MAAM,GAAG,CAAC,EAAE;AAC3C,UAAA,MAAMX,KAAK,GAAGO,YAAY,CAACD,OAAO,EAAE;AAAEzB,YAAAA;AAAU,WAAC,CAAC;AAClD,UAAA,IAAImB,KAAK,EAAE;AACT,YAAA,MAAMQ,SAAS,GAAG1B,eAAe,CAAC2B,IAAI,CAAED,SAAS,IAC/CA,SAAS,CAACR,KAA6B,CACzC,CAAC,GAAGA,KAA6B,CAAC;AAClC,YAAA,IAAIQ,SAAS,IAAIA,SAAS,CAACE,cAAc,EAAE;AACzC,cAAA,OAAOF,SAAS,CAACE,cAAc,CAACJ,OAAO,CAAC;AAC1C,YAAA;AACF,UAAA;AACF,QAAA;QACA,OAAOM,qBAAqB,CAACN,OAAO,CAAC;AACvC,MAAA;AACF,KAAC,CACF;IACDN,KAAK,EAAEa,YAAY,CAAC;AAAEhC,MAAAA;KAAW;GAClC;AACH,CAAC;AAEM,MAAMiC,oBAAoB,GAAIC,OAAiB,IACpDC,mBAAmB,CAACpC,eAAe,CAACmC,OAAO,CAAC;AAEvC,MAAME,wBAAwB,GAAIF,OAAiB,IACxDG,mBAAmB,CAACtC,eAAe,CAACmC,OAAO,CAAC;;;;"}
@@ -0,0 +1,82 @@
1
+ import { InputRule } from 'prosemirror-inputrules';
2
+ import { defaultLinkParser } from './parser.js';
3
+
4
+ const DEFAULT_REGEX = new RegExp(String.raw`
5
+ (^|\s)
6
+ (
7
+ (?: ${/* parse email */''}
8
+ (?:mailto:)? ${/* optional mailto: protocol */''}
9
+ [A-Za-z0-9._%+-]+ ${/* local-part */''}
10
+ @
11
+ [A-Za-z0-9.-]+ ${/* domain */''}
12
+ \.
13
+ [A-Za-z]{2,} ${/* extension */''}
14
+ )
15
+ |
16
+ (?: ${/* parse weblinks */''}
17
+ (?:https?:\/\/)? ${/* optional http(s): protocol */''}
18
+ (?:www\.)? ${/* optional www */''}
19
+ [A-Za-z0-9.-]+ ${/* domain */''}
20
+ \.
21
+ [A-Za-z]{2,} ${/* extension */''}
22
+ )
23
+ )
24
+ (\s)$ ${/* single space after url/email */''}
25
+ `.replace(/^\s+|\s+$/gm, '') // remove white space before and at the end of lines (trimming)
26
+ .replace(/\n/g, '')) // remove newlines
27
+ ;
28
+
29
+ /**
30
+ * Input rule which is able to detect plain text links and convert them to a link object.
31
+ * It may be configured with a `nodeType`, a custom `regex` and a custom `linkParser`.
32
+ *
33
+ * If using a custom `regex`, it should meet the following conditions:
34
+ * - The first group should capture the text typed before the (possible) link
35
+ * - The second group should capture the text representing the (possible) link
36
+ * - The third group should capture the text typed after the (possible) link
37
+ */
38
+ const link_input_rule = ({
39
+ nodeType,
40
+ regex = DEFAULT_REGEX,
41
+ linkParser = defaultLinkParser()
42
+ }) => {
43
+ return new InputRule(regex, (state, match, start, end) => {
44
+ // Ensure both the start and end of the input-rule match are within the same parent node
45
+ if (state.doc.resolve(start).parent !== state.doc.resolve(end).parent) {
46
+ return null;
47
+ }
48
+ if (!rangeContainsOnlyText(state.doc, start, end)) {
49
+ return null;
50
+ }
51
+ const textBeforeLink = match[1];
52
+ const link = match[2];
53
+ const textAfterLink = match[3];
54
+ const linkStart = start + textBeforeLink.length;
55
+ const linkParserResult = linkParser(link);
56
+ if (!linkParserResult.isSuccessful) {
57
+ return null;
58
+ }
59
+ const node = nodeType.create({
60
+ href: linkParserResult.value
61
+ }, state.schema.text(link));
62
+ const tr = state.tr;
63
+
64
+ // replace only the email text
65
+ tr.replaceWith(linkStart, end, node);
66
+ tr.insertText(textAfterLink, linkStart + node.nodeSize);
67
+ return tr;
68
+ });
69
+ };
70
+ const rangeContainsOnlyText = (doc, from, to) => {
71
+ let onlyText = true;
72
+ doc.nodesBetween(from, to, node => {
73
+ if (node.isInline && !node.isText) {
74
+ onlyText = false;
75
+ return false;
76
+ }
77
+ });
78
+ return onlyText;
79
+ };
80
+
81
+ export { link_input_rule };
82
+ //# sourceMappingURL=input-rule.js.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"input-rule.js","sources":["../../../src/plugins/link/input-rule.ts"],"sourcesContent":["import { InputRule } from 'prosemirror-inputrules';\nimport { defaultLinkParser, type LinkParser } from './parser.ts';\nimport type { NodeType } from 'prosemirror-model';\nimport type { PNode } from '#root/prosemirror-aliases.ts';\n\ntype LinkInputRuleOptions = {\n nodeType: NodeType;\n regex?: RegExp;\n linkParser?: LinkParser;\n};\n\nconst DEFAULT_REGEX = new RegExp(\n String.raw`\n (^|\\s)\n (\n (?: ${/* parse email */ ''}\n (?:mailto:)? ${/* optional mailto: protocol */ ''}\n [A-Za-z0-9._%+-]+ ${/* local-part */ ''}\n @\n [A-Za-z0-9.-]+ ${/* domain */ ''}\n \\.\n [A-Za-z]{2,} ${/* extension */ ''}\n )\n |\n (?: ${/* parse weblinks */ ''}\n (?:https?:\\/\\/)? ${/* optional http(s): protocol */ ''}\n (?:www\\.)? ${/* optional www */ ''}\n [A-Za-z0-9.-]+ ${/* domain */ ''}\n \\.\n [A-Za-z]{2,} ${/* extension */ ''}\n )\n )\n (\\s)$ ${/* single space after url/email */ ''}\n `\n .replace(/^\\s+|\\s+$/gm, '') // remove white space before and at the end of lines (trimming)\n .replace(/\\n/g, ''), // remove newlines\n);\n\n/**\n * Input rule which is able to detect plain text links and convert them to a link object.\n * It may be configured with a `nodeType`, a custom `regex` and a custom `linkParser`.\n *\n * If using a custom `regex`, it should meet the following conditions:\n * - The first group should capture the text typed before the (possible) link\n * - The second group should capture the text representing the (possible) link\n * - The third group should capture the text typed after the (possible) link\n */\nexport const link_input_rule = ({\n nodeType,\n regex = DEFAULT_REGEX,\n linkParser = defaultLinkParser(),\n}: LinkInputRuleOptions) => {\n return new InputRule(regex, (state, match, start, end) => {\n // Ensure both the start and end of the input-rule match are within the same parent node\n if (state.doc.resolve(start).parent !== state.doc.resolve(end).parent) {\n return null;\n }\n\n if (!rangeContainsOnlyText(state.doc, start, end)) {\n return null;\n }\n\n const textBeforeLink = match[1];\n const link = match[2];\n const textAfterLink = match[3];\n const linkStart = start + textBeforeLink.length;\n\n const linkParserResult = linkParser(link);\n if (!linkParserResult.isSuccessful) {\n return null;\n }\n const node = nodeType.create(\n {\n href: linkParserResult.value,\n },\n state.schema.text(link),\n );\n const tr = state.tr;\n\n // replace only the email text\n tr.replaceWith(linkStart, end, node);\n\n tr.insertText(textAfterLink, linkStart + node.nodeSize);\n\n return tr;\n });\n};\n\nconst rangeContainsOnlyText = (doc: PNode, from: number, to: number) => {\n let onlyText = true;\n doc.nodesBetween(from, to, (node) => {\n if (node.isInline && !node.isText) {\n onlyText = false;\n return false;\n }\n });\n return onlyText;\n};\n"],"names":["DEFAULT_REGEX","RegExp","String","raw","replace","link_input_rule","nodeType","regex","linkParser","defaultLinkParser","InputRule","state","match","start","end","doc","resolve","parent","rangeContainsOnlyText","textBeforeLink","link","textAfterLink","linkStart","length","linkParserResult","isSuccessful","node","create","href","value","schema","text","tr","replaceWith","insertText","nodeSize","from","to","onlyText","nodesBetween","isInline","isText"],"mappings":"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"}
@@ -2,13 +2,15 @@ import getClassnamesFromNode from '../../../utils/get-classnames-from-node.js';
2
2
  import { renderRdfaAware, getRdfaContentElement, getRdfaAttrs, rdfaAttrSpec } from '../../../core/schema.js';
3
3
  import { createEmberNodeSpec, createEmberNodeView } from '../../../utils/_private/ember-node.js';
4
4
  import Link from '../../../components/ember-node/link.js';
5
+ import { defaultLinkParser } from '../parser.js';
5
6
 
6
7
  // TODO this spec doesn't play well with RDFa editing tools. It has been modified so that any
7
8
  // additional RDFa annotations are not striped. This is for example, used by the citation plugin in
8
9
  // lblod-plugins
9
10
  const emberNodeConfig = ({
10
11
  interactive = false,
11
- rdfaAware = false
12
+ rdfaAware = false,
13
+ linkParser = defaultLinkParser()
12
14
  } = {}) => {
13
15
  return {
14
16
  name: 'link',
@@ -27,6 +29,12 @@ const emberNodeConfig = ({
27
29
  },
28
30
  interactive: {
29
31
  default: interactive
32
+ },
33
+ linkParser: {
34
+ default: linkParser
35
+ },
36
+ isNew: {
37
+ default: false
30
38
  }
31
39
  };
32
40
  return {
@@ -62,6 +70,8 @@ const emberNodeConfig = ({
62
70
  } = node.attrs;
63
71
  delete attrs['interactive'];
64
72
  delete attrs['placeholder'];
73
+ delete attrs['linkParser'];
74
+ delete attrs['isNew'];
65
75
  if (rdfaAware) {
66
76
  return renderRdfaAware({
67
77
  renderable: node,
@@ -1 +1 @@
1
- {"version":3,"file":"link.js","sources":["../../../../src/plugins/link/nodes/link.ts"],"sourcesContent":["import getClassnamesFromNode from '#root/utils/get-classnames-from-node.ts';\nimport {\n getRdfaAttrs,\n getRdfaContentElement,\n rdfaAttrSpec,\n renderRdfaAware,\n} from '../../../core/schema.ts';\nimport {\n createEmberNodeSpec,\n createEmberNodeView,\n type EmberNodeConfig,\n} from '../../../utils/ember-node.ts';\nimport type { ComponentLike } from '@glint/template';\nimport Link from '#root/components/ember-node/link.ts';\n\ntype LinkOptions = {\n interactive?: boolean;\n rdfaAware?: boolean;\n};\n\n// TODO this spec doesn't play well with RDFa editing tools. It has been modified so that any\n// additional RDFa annotations are not striped. This is for example, used by the citation plugin in\n// lblod-plugins\nconst emberNodeConfig: (options?: LinkOptions) => EmberNodeConfig = ({\n interactive = false,\n rdfaAware = false,\n} = {}) => {\n return {\n name: 'link',\n component: Link as unknown as ComponentLike,\n inline: true,\n group: 'inline',\n content: 'text*',\n atom: true,\n defining: true,\n draggable: false,\n classNames: ['say-pill', 'say-link'],\n get attrs() {\n const baseAttrs = {\n href: {\n default: null,\n },\n interactive: {\n default: interactive,\n },\n };\n return {\n ...rdfaAttrSpec({ rdfaAware }),\n ...baseAttrs,\n };\n },\n needsFFKludge: true,\n needsChromeCursorFix: true,\n get parseDOM() {\n return [\n {\n tag: 'a',\n getAttrs(dom: string | HTMLElement) {\n if (typeof dom === 'string') {\n return false;\n }\n const href = dom.getAttribute('href');\n return {\n ...getRdfaAttrs(dom, { rdfaAware }),\n href,\n };\n },\n contentElement: getRdfaContentElement,\n },\n ];\n },\n toDOM(node) {\n const { ...attrs }: Record<string, unknown> = node.attrs;\n delete attrs['interactive'];\n delete attrs['placeholder'];\n if (rdfaAware) {\n return renderRdfaAware({\n renderable: node,\n tag: 'a',\n attrs: { ...attrs, class: getClassnamesFromNode(node) },\n content: 0,\n });\n } else {\n return ['a', { ...attrs, class: getClassnamesFromNode(node) }, 0];\n }\n },\n };\n};\n\nexport const link = (options?: LinkOptions) =>\n createEmberNodeSpec(emberNodeConfig(options));\n\nexport const linkView = (options?: LinkOptions) =>\n createEmberNodeView(emberNodeConfig(options));\n"],"names":["emberNodeConfig","interactive","rdfaAware","name","component","Link","inline","group","content","atom","defining","draggable","classNames","attrs","baseAttrs","href","default","rdfaAttrSpec","needsFFKludge","needsChromeCursorFix","parseDOM","tag","getAttrs","dom","getAttribute","getRdfaAttrs","contentElement","getRdfaContentElement","toDOM","node","renderRdfaAware","renderable","class","getClassnamesFromNode","link","options","createEmberNodeSpec","linkView","createEmberNodeView"],"mappings":";;;;;AAoBA;AACA;AACA;AACA,MAAMA,eAA2D,GAAGA,CAAC;AACnEC,EAAAA,WAAW,GAAG,KAAK;AACnBC,EAAAA,SAAS,GAAG;AACd,CAAC,GAAG,EAAE,KAAK;EACT,OAAO;AACLC,IAAAA,IAAI,EAAE,MAAM;AACZC,IAAAA,SAAS,EAAEC,IAAgC;AAC3CC,IAAAA,MAAM,EAAE,IAAI;AACZC,IAAAA,KAAK,EAAE,QAAQ;AACfC,IAAAA,OAAO,EAAE,OAAO;AAChBC,IAAAA,IAAI,EAAE,IAAI;AACVC,IAAAA,QAAQ,EAAE,IAAI;AACdC,IAAAA,SAAS,EAAE,KAAK;AAChBC,IAAAA,UAAU,EAAE,CAAC,UAAU,EAAE,UAAU,CAAC;IACpC,IAAIC,KAAKA,GAAG;AACV,MAAA,MAAMC,SAAS,GAAG;AAChBC,QAAAA,IAAI,EAAE;AACJC,UAAAA,OAAO,EAAE;SACV;AACDf,QAAAA,WAAW,EAAE;AACXe,UAAAA,OAAO,EAAEf;AACX;OACD;MACD,OAAO;AACL,QAAA,GAAGgB,YAAY,CAAC;AAAEf,UAAAA;AAAU,SAAC,CAAC;QAC9B,GAAGY;OACJ;IACH,CAAC;AACDI,IAAAA,aAAa,EAAE,IAAI;AACnBC,IAAAA,oBAAoB,EAAE,IAAI;IAC1B,IAAIC,QAAQA,GAAG;AACb,MAAA,OAAO,CACL;AACEC,QAAAA,GAAG,EAAE,GAAG;QACRC,QAAQA,CAACC,GAAyB,EAAE;AAClC,UAAA,IAAI,OAAOA,GAAG,KAAK,QAAQ,EAAE;AAC3B,YAAA,OAAO,KAAK;AACd,UAAA;AACA,UAAA,MAAMR,IAAI,GAAGQ,GAAG,CAACC,YAAY,CAAC,MAAM,CAAC;UACrC,OAAO;YACL,GAAGC,YAAY,CAACF,GAAG,EAAE;AAAErB,cAAAA;AAAU,aAAC,CAAC;AACnCa,YAAAA;WACD;QACH,CAAC;AACDW,QAAAA,cAAc,EAAEC;AAClB,OAAC,CACF;IACH,CAAC;IACDC,KAAKA,CAACC,IAAI,EAAE;MACV,MAAM;QAAE,GAAGhB;OAAgC,GAAGgB,IAAI,CAAChB,KAAK;MACxD,OAAOA,KAAK,CAAC,aAAa,CAAC;MAC3B,OAAOA,KAAK,CAAC,aAAa,CAAC;AAC3B,MAAA,IAAIX,SAAS,EAAE;AACb,QAAA,OAAO4B,eAAe,CAAC;AACrBC,UAAAA,UAAU,EAAEF,IAAI;AAChBR,UAAAA,GAAG,EAAE,GAAG;AACRR,UAAAA,KAAK,EAAE;AAAE,YAAA,GAAGA,KAAK;YAAEmB,KAAK,EAAEC,qBAAqB,CAACJ,IAAI;WAAG;AACvDrB,UAAAA,OAAO,EAAE;AACX,SAAC,CAAC;AACJ,MAAA,CAAC,MAAM;QACL,OAAO,CAAC,GAAG,EAAE;AAAE,UAAA,GAAGK,KAAK;UAAEmB,KAAK,EAAEC,qBAAqB,CAACJ,IAAI;SAAG,EAAE,CAAC,CAAC;AACnE,MAAA;AACF,IAAA;GACD;AACH,CAAC;AAEM,MAAMK,IAAI,GAAIC,OAAqB,IACxCC,mBAAmB,CAACpC,eAAe,CAACmC,OAAO,CAAC;AAEvC,MAAME,QAAQ,GAAIF,OAAqB,IAC5CG,mBAAmB,CAACtC,eAAe,CAACmC,OAAO,CAAC;;;;"}
1
+ {"version":3,"file":"link.js","sources":["../../../../src/plugins/link/nodes/link.ts"],"sourcesContent":["import getClassnamesFromNode from '#root/utils/get-classnames-from-node.ts';\nimport {\n getRdfaAttrs,\n getRdfaContentElement,\n rdfaAttrSpec,\n renderRdfaAware,\n} from '../../../core/schema.ts';\nimport {\n createEmberNodeSpec,\n createEmberNodeView,\n type EmberNodeConfig,\n} from '../../../utils/ember-node.ts';\nimport type { ComponentLike } from '@glint/template';\nimport Link from '#root/components/ember-node/link.gts';\nimport { defaultLinkParser, type LinkParser } from '../parser.ts';\n\ntype LinkOptions = {\n interactive?: boolean;\n rdfaAware?: boolean;\n linkParser?: LinkParser;\n};\n\n// TODO this spec doesn't play well with RDFa editing tools. It has been modified so that any\n// additional RDFa annotations are not striped. This is for example, used by the citation plugin in\n// lblod-plugins\nconst emberNodeConfig: (options?: LinkOptions) => EmberNodeConfig = ({\n interactive = false,\n rdfaAware = false,\n linkParser = defaultLinkParser(),\n} = {}) => {\n return {\n name: 'link',\n component: Link as unknown as ComponentLike,\n inline: true,\n group: 'inline',\n content: 'text*',\n atom: true,\n defining: true,\n draggable: false,\n classNames: ['say-pill', 'say-link'],\n get attrs() {\n const baseAttrs = {\n href: {\n default: null,\n },\n interactive: {\n default: interactive,\n },\n linkParser: {\n default: linkParser,\n },\n isNew: {\n default: false,\n },\n };\n return {\n ...rdfaAttrSpec({ rdfaAware }),\n ...baseAttrs,\n };\n },\n needsFFKludge: true,\n needsChromeCursorFix: true,\n get parseDOM() {\n return [\n {\n tag: 'a',\n getAttrs(dom: string | HTMLElement) {\n if (typeof dom === 'string') {\n return false;\n }\n const href = dom.getAttribute('href');\n return {\n ...getRdfaAttrs(dom, { rdfaAware }),\n href,\n };\n },\n contentElement: getRdfaContentElement,\n },\n ];\n },\n toDOM(node) {\n const { ...attrs }: Record<string, unknown> = node.attrs;\n delete attrs['interactive'];\n delete attrs['placeholder'];\n delete attrs['linkParser'];\n delete attrs['isNew'];\n if (rdfaAware) {\n return renderRdfaAware({\n renderable: node,\n tag: 'a',\n attrs: { ...attrs, class: getClassnamesFromNode(node) },\n content: 0,\n });\n } else {\n return ['a', { ...attrs, class: getClassnamesFromNode(node) }, 0];\n }\n },\n };\n};\n\nexport const link = (options?: LinkOptions) =>\n createEmberNodeSpec(emberNodeConfig(options));\n\nexport const linkView = (options?: LinkOptions) =>\n createEmberNodeView(emberNodeConfig(options));\n"],"names":["emberNodeConfig","interactive","rdfaAware","linkParser","defaultLinkParser","name","component","Link","inline","group","content","atom","defining","draggable","classNames","attrs","baseAttrs","href","default","isNew","rdfaAttrSpec","needsFFKludge","needsChromeCursorFix","parseDOM","tag","getAttrs","dom","getAttribute","getRdfaAttrs","contentElement","getRdfaContentElement","toDOM","node","renderRdfaAware","renderable","class","getClassnamesFromNode","link","options","createEmberNodeSpec","linkView","createEmberNodeView"],"mappings":";;;;;;AAsBA;AACA;AACA;AACA,MAAMA,eAA2D,GAAGA,CAAC;AACnEC,EAAAA,WAAW,GAAG,KAAK;AACnBC,EAAAA,SAAS,GAAG,KAAK;EACjBC,UAAU,GAAGC,iBAAiB;AAChC,CAAC,GAAG,EAAE,KAAK;EACT,OAAO;AACLC,IAAAA,IAAI,EAAE,MAAM;AACZC,IAAAA,SAAS,EAAEC,IAAgC;AAC3CC,IAAAA,MAAM,EAAE,IAAI;AACZC,IAAAA,KAAK,EAAE,QAAQ;AACfC,IAAAA,OAAO,EAAE,OAAO;AAChBC,IAAAA,IAAI,EAAE,IAAI;AACVC,IAAAA,QAAQ,EAAE,IAAI;AACdC,IAAAA,SAAS,EAAE,KAAK;AAChBC,IAAAA,UAAU,EAAE,CAAC,UAAU,EAAE,UAAU,CAAC;IACpC,IAAIC,KAAKA,GAAG;AACV,MAAA,MAAMC,SAAS,GAAG;AAChBC,QAAAA,IAAI,EAAE;AACJC,UAAAA,OAAO,EAAE;SACV;AACDjB,QAAAA,WAAW,EAAE;AACXiB,UAAAA,OAAO,EAAEjB;SACV;AACDE,QAAAA,UAAU,EAAE;AACVe,UAAAA,OAAO,EAAEf;SACV;AACDgB,QAAAA,KAAK,EAAE;AACLD,UAAAA,OAAO,EAAE;AACX;OACD;MACD,OAAO;AACL,QAAA,GAAGE,YAAY,CAAC;AAAElB,UAAAA;AAAU,SAAC,CAAC;QAC9B,GAAGc;OACJ;IACH,CAAC;AACDK,IAAAA,aAAa,EAAE,IAAI;AACnBC,IAAAA,oBAAoB,EAAE,IAAI;IAC1B,IAAIC,QAAQA,GAAG;AACb,MAAA,OAAO,CACL;AACEC,QAAAA,GAAG,EAAE,GAAG;QACRC,QAAQA,CAACC,GAAyB,EAAE;AAClC,UAAA,IAAI,OAAOA,GAAG,KAAK,QAAQ,EAAE;AAC3B,YAAA,OAAO,KAAK;AACd,UAAA;AACA,UAAA,MAAMT,IAAI,GAAGS,GAAG,CAACC,YAAY,CAAC,MAAM,CAAC;UACrC,OAAO;YACL,GAAGC,YAAY,CAACF,GAAG,EAAE;AAAExB,cAAAA;AAAU,aAAC,CAAC;AACnCe,YAAAA;WACD;QACH,CAAC;AACDY,QAAAA,cAAc,EAAEC;AAClB,OAAC,CACF;IACH,CAAC;IACDC,KAAKA,CAACC,IAAI,EAAE;MACV,MAAM;QAAE,GAAGjB;OAAgC,GAAGiB,IAAI,CAACjB,KAAK;MACxD,OAAOA,KAAK,CAAC,aAAa,CAAC;MAC3B,OAAOA,KAAK,CAAC,aAAa,CAAC;MAC3B,OAAOA,KAAK,CAAC,YAAY,CAAC;MAC1B,OAAOA,KAAK,CAAC,OAAO,CAAC;AACrB,MAAA,IAAIb,SAAS,EAAE;AACb,QAAA,OAAO+B,eAAe,CAAC;AACrBC,UAAAA,UAAU,EAAEF,IAAI;AAChBR,UAAAA,GAAG,EAAE,GAAG;AACRT,UAAAA,KAAK,EAAE;AAAE,YAAA,GAAGA,KAAK;YAAEoB,KAAK,EAAEC,qBAAqB,CAACJ,IAAI;WAAG;AACvDtB,UAAAA,OAAO,EAAE;AACX,SAAC,CAAC;AACJ,MAAA,CAAC,MAAM;QACL,OAAO,CAAC,GAAG,EAAE;AAAE,UAAA,GAAGK,KAAK;UAAEoB,KAAK,EAAEC,qBAAqB,CAACJ,IAAI;SAAG,EAAE,CAAC,CAAC;AACnE,MAAA;AACF,IAAA;GACD;AACH,CAAC;AAEM,MAAMK,IAAI,GAAIC,OAAqB,IACxCC,mBAAmB,CAACvC,eAAe,CAACsC,OAAO,CAAC;AAEvC,MAAME,QAAQ,GAAIF,OAAqB,IAC5CG,mBAAmB,CAACzC,eAAe,CAACsC,OAAO,CAAC;;;;"}
@@ -0,0 +1,58 @@
1
+ import { test, find } from 'linkifyjs';
2
+ import parsePhoneNumber from 'libphonenumber-js';
3
+
4
+ const defaultLinkParser = ({
5
+ defaultCountryCode = 'BE',
6
+ supportedProtocols = ['http:', 'https:', 'mailto:', 'tel:', 'sms:']
7
+ } = {}) => {
8
+ return input => {
9
+ const link = input?.trim();
10
+ if (!link) {
11
+ return {
12
+ isSuccessful: false,
13
+ errors: ['URL mag niet leeg zijn']
14
+ };
15
+ }
16
+ let href;
17
+ if (test(link)) {
18
+ href = find(link)[0].href;
19
+ }
20
+ if (!href) {
21
+ const phoneNumber = parsePhoneNumber(link, defaultCountryCode);
22
+ if (phoneNumber) {
23
+ const phoneNumberUri = phoneNumber.getURI();
24
+ const value = link.startsWith('sms:') ?
25
+ // libphonenumber-js transforms sms: automatically to tel:, so revert this transform if necessary
26
+ phoneNumberUri.replace('tel:', 'sms:') : phoneNumberUri;
27
+ href = value;
28
+ }
29
+ }
30
+ if (!href) {
31
+ return {
32
+ isSuccessful: false,
33
+ errors: ['De ingegeven URL/link is niet geldig']
34
+ };
35
+ }
36
+ if (!hasSupportedProtocol(href, supportedProtocols)) {
37
+ return {
38
+ isSuccessful: false,
39
+ errors: ['de ingegeven URL/link is niet toegestaan']
40
+ };
41
+ }
42
+ return {
43
+ isSuccessful: true,
44
+ value: href
45
+ };
46
+ };
47
+ };
48
+ const hasSupportedProtocol = (href, supportedProtocols) => {
49
+ try {
50
+ const protocol = new URL(href).protocol;
51
+ return supportedProtocols.includes(protocol);
52
+ } catch {
53
+ return false;
54
+ }
55
+ };
56
+
57
+ export { defaultLinkParser };
58
+ //# sourceMappingURL=parser.js.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"parser.js","sources":["../../../src/plugins/link/parser.ts"],"sourcesContent":["import { find as linkifyFind, test as linkifyTest } from 'linkifyjs';\nimport parsePhoneNumber, { type CountryCode } from 'libphonenumber-js';\n\nexport type LinkParserResult =\n | {\n isSuccessful: true;\n value: string;\n errors?: never;\n }\n | {\n isSuccessful: false;\n value?: never;\n errors: [string, ...string[]];\n };\nexport type LinkParser = (input?: string) => LinkParserResult;\n\ntype DefaultLinkParserOptions = {\n defaultCountryCode?: CountryCode;\n supportedProtocols?: string[];\n};\n\nexport const defaultLinkParser = ({\n defaultCountryCode = 'BE',\n supportedProtocols = ['http:', 'https:', 'mailto:', 'tel:', 'sms:'],\n}: DefaultLinkParserOptions = {}): LinkParser => {\n return (input?: string) => {\n const link = input?.trim();\n if (!link) {\n return { isSuccessful: false, errors: ['URL mag niet leeg zijn'] };\n }\n\n let href: string | undefined;\n\n if (linkifyTest(link)) {\n href = linkifyFind(link)[0].href;\n }\n\n if (!href) {\n const phoneNumber = parsePhoneNumber(link, defaultCountryCode);\n if (phoneNumber) {\n const phoneNumberUri = phoneNumber.getURI();\n const value = link.startsWith('sms:')\n ? // libphonenumber-js transforms sms: automatically to tel:, so revert this transform if necessary\n phoneNumberUri.replace('tel:', 'sms:')\n : phoneNumberUri;\n href = value;\n }\n }\n if (!href) {\n return {\n isSuccessful: false,\n errors: ['De ingegeven URL/link is niet geldig'],\n };\n }\n\n if (!hasSupportedProtocol(href, supportedProtocols)) {\n return {\n isSuccessful: false,\n errors: ['de ingegeven URL/link is niet toegestaan'],\n };\n }\n\n return {\n isSuccessful: true,\n value: href,\n };\n };\n};\n\nconst hasSupportedProtocol = (href: string, supportedProtocols: string[]) => {\n try {\n const protocol = new URL(href).protocol;\n return supportedProtocols.includes(protocol);\n } catch {\n return false;\n }\n};\n"],"names":["defaultLinkParser","defaultCountryCode","supportedProtocols","input","link","trim","isSuccessful","errors","href","linkifyTest","linkifyFind","phoneNumber","parsePhoneNumber","phoneNumberUri","getURI","value","startsWith","replace","hasSupportedProtocol","protocol","URL","includes"],"mappings":";;;AAqBO,MAAMA,iBAAiB,GAAGA,CAAC;AAChCC,EAAAA,kBAAkB,GAAG,IAAI;EACzBC,kBAAkB,GAAG,CAAC,OAAO,EAAE,QAAQ,EAAE,SAAS,EAAE,MAAM,EAAE,MAAM;AAC1C,CAAC,GAAG,EAAE,KAAiB;AAC/C,EAAA,OAAQC,KAAc,IAAK;AACzB,IAAA,MAAMC,IAAI,GAAGD,KAAK,EAAEE,IAAI,EAAE;IAC1B,IAAI,CAACD,IAAI,EAAE;MACT,OAAO;AAAEE,QAAAA,YAAY,EAAE,KAAK;QAAEC,MAAM,EAAE,CAAC,wBAAwB;OAAG;AACpE,IAAA;AAEA,IAAA,IAAIC,IAAwB;AAE5B,IAAA,IAAIC,IAAW,CAACL,IAAI,CAAC,EAAE;MACrBI,IAAI,GAAGE,IAAW,CAACN,IAAI,CAAC,CAAC,CAAC,CAAC,CAACI,IAAI;AAClC,IAAA;IAEA,IAAI,CAACA,IAAI,EAAE;AACT,MAAA,MAAMG,WAAW,GAAGC,gBAAgB,CAACR,IAAI,EAAEH,kBAAkB,CAAC;AAC9D,MAAA,IAAIU,WAAW,EAAE;AACf,QAAA,MAAME,cAAc,GAAGF,WAAW,CAACG,MAAM,EAAE;AAC3C,QAAA,MAAMC,KAAK,GAAGX,IAAI,CAACY,UAAU,CAAC,MAAM,CAAC;AACjC;QACAH,cAAc,CAACI,OAAO,CAAC,MAAM,EAAE,MAAM,CAAC,GACtCJ,cAAc;AAClBL,QAAAA,IAAI,GAAGO,KAAK;AACd,MAAA;AACF,IAAA;IACA,IAAI,CAACP,IAAI,EAAE;MACT,OAAO;AACLF,QAAAA,YAAY,EAAE,KAAK;QACnBC,MAAM,EAAE,CAAC,sCAAsC;OAChD;AACH,IAAA;AAEA,IAAA,IAAI,CAACW,oBAAoB,CAACV,IAAI,EAAEN,kBAAkB,CAAC,EAAE;MACnD,OAAO;AACLI,QAAAA,YAAY,EAAE,KAAK;QACnBC,MAAM,EAAE,CAAC,0CAA0C;OACpD;AACH,IAAA;IAEA,OAAO;AACLD,MAAAA,YAAY,EAAE,IAAI;AAClBS,MAAAA,KAAK,EAAEP;KACR;EACH,CAAC;AACH;AAEA,MAAMU,oBAAoB,GAAGA,CAACV,IAAY,EAAEN,kBAA4B,KAAK;EAC3E,IAAI;IACF,MAAMiB,QAAQ,GAAG,IAAIC,GAAG,CAACZ,IAAI,CAAC,CAACW,QAAQ;AACvC,IAAA,OAAOjB,kBAAkB,CAACmB,QAAQ,CAACF,QAAQ,CAAC;AAC9C,EAAA,CAAC,CAAC,MAAM;AACN,IAAA,OAAO,KAAK;AACd,EAAA;AACF,CAAC;;;;"}
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "@lblod/ember-rdfa-editor",
3
- "version": "13.2.1",
3
+ "version": "13.3.0",
4
4
  "description": "Ember addon wrapping an RDFa editor with a public API",
5
5
  "keywords": [
6
6
  "ember-addon"
@@ -239,6 +239,7 @@
239
239
  "ember-velcro": "^2.2.0",
240
240
  "iter-tools": "^7.5.4",
241
241
  "js-beautify": "^1.15.4",
242
+ "libphonenumber-js": "^1.12.38",
242
243
  "linkifyjs": "^4.3.2",
243
244
  "mdn-polyfills": "^5.20.0",
244
245
  "mongoose": "^8.21.0",
@@ -397,8 +398,10 @@
397
398
  "./components/plugins/image/insert-menu.js": "./dist/_app_/components/plugins/image/insert-menu.js",
398
399
  "./components/plugins/image/node.js": "./dist/_app_/components/plugins/image/node.js",
399
400
  "./components/plugins/indentation/indentation-menu.js": "./dist/_app_/components/plugins/indentation/indentation-menu.js",
401
+ "./components/plugins/link/_private/link-editor.js": "./dist/_app_/components/plugins/link/_private/link-editor.js",
400
402
  "./components/plugins/link/link-editor.js": "./dist/_app_/components/plugins/link/link-editor.js",
401
403
  "./components/plugins/link/link-menu.js": "./dist/_app_/components/plugins/link/link-menu.js",
404
+ "./components/plugins/link/link-sidebar-widget.js": "./dist/_app_/components/plugins/link/link-sidebar-widget.js",
402
405
  "./components/plugins/list/indentation-controls.js": "./dist/_app_/components/plugins/list/indentation-controls.js",
403
406
  "./components/plugins/list/ordered.js": "./dist/_app_/components/plugins/list/ordered.js",
404
407
  "./components/plugins/list/unordered.js": "./dist/_app_/components/plugins/list/unordered.js",
@@ -23,7 +23,6 @@
23
23
  width: 0;
24
24
  top: 0;
25
25
  left: 0;
26
- z-index: 1;
27
26
  }
28
27
  &.invisible--space::before {
29
28
  content: "\00B7";
package/scss/_c-link.scss CHANGED
@@ -1,35 +1,15 @@
1
1
  @use "@appuniversum/ember-appuniversum/styles/settings/s-root";
2
+ @use "@appuniversum/ember-appuniversum/styles/a-settings" as au-settings;
2
3
 
3
- .say-link-tooltip {
4
- z-index: 3;
5
- background-color: var(--au-white);
6
- gap: 0;
7
- align-items: stretch;
8
- padding: 0;
9
- width: 28rem;
10
-
11
- a,
12
- button {
13
- padding: 0;
14
- flex: 1;
15
- border: 0;
16
- justify-content: center;
17
- }
18
-
19
- .au-c-input {
20
- border-width: 0 0.1rem;
21
- border-radius: 0%;
22
- padding: 0 0.3rem;
23
- flex: 7;
24
- }
25
-
26
- .au-c-input:focus {
27
- border-width: 0 0 !important;
28
- }
4
+ .say-link-editor {
5
+ height: auto;
6
+ z-index: 1;
7
+ background: var(--au-gray-100);
8
+ border: 0.1rem solid var(--au-gray-300);
9
+ border-radius: 0.5rem;
29
10
  }
30
11
 
31
12
  .say-pill {
32
- gap: 0;
33
13
  vertical-align: bottom;
34
14
  min-height: 2.55rem;
35
15
  margin-bottom: -0.1rem;
@@ -47,6 +27,17 @@
47
27
  cursor: text;
48
28
  color: var(--au-blue-700);
49
29
  }
30
+
31
+ &--error {
32
+ color: var(--au-red-700);
33
+ background-color: var(--au-red-200);
34
+ border-color: var(--au-red-300);
35
+ text-decoration-color: var(--au-red-300);
36
+
37
+ [contenteditable] {
38
+ color: var(--au-red-700);
39
+ }
40
+ }
50
41
  }
51
42
 
52
43
  .ember-node.ProseMirror-selectednode {
@@ -58,5 +49,14 @@
58
49
  ::selection {
59
50
  background-color: var(--au-blue-300);
60
51
  }
52
+
53
+ &--error {
54
+ background-color: var(--au-red-200);
55
+ outline: 2px solid var(--au-red-500);
56
+
57
+ ::selection {
58
+ background-color: var(--au-red-300);
59
+ }
60
+ }
61
61
  }
62
62
  }
@@ -94,6 +94,10 @@ table.ProseMirror-selectednode,
94
94
  .say-table-tooltip {
95
95
  display: flex;
96
96
  flex-direction: column;
97
+ box-shadow:
98
+ 0 1px 3px rgba(au-settings.$au-gray-900, 0.1),
99
+ 0 4px 20px rgba(au-settings.$au-gray-900, 0.035),
100
+ 0 1px 1px rgba(au-settings.$au-gray-900, 0.025);
97
101
 
98
102
  .color-selector__grid {
99
103
  padding: 0 12px;
@@ -1159,33 +1159,15 @@
1159
1159
  --au-z-index-gamma: 3;
1160
1160
  }
1161
1161
 
1162
- .say-link-tooltip {
1163
- z-index: 3;
1164
- background-color: var(--au-white);
1165
- gap: 0;
1166
- align-items: stretch;
1167
- padding: 0;
1168
- width: 28rem;
1169
- }
1170
- .say-link-tooltip a,
1171
- .say-link-tooltip button {
1172
- padding: 0;
1173
- flex: 1;
1174
- border: 0;
1175
- justify-content: center;
1176
- }
1177
- .say-link-tooltip .au-c-input {
1178
- border-width: 0 0.1rem;
1179
- border-radius: 0%;
1180
- padding: 0 0.3rem;
1181
- flex: 7;
1182
- }
1183
- .say-link-tooltip .au-c-input:focus {
1184
- border-width: 0 0 !important;
1162
+ .say-link-editor {
1163
+ height: auto;
1164
+ z-index: 1;
1165
+ background: var(--au-gray-100);
1166
+ border: 0.1rem solid var(--au-gray-300);
1167
+ border-radius: 0.5rem;
1185
1168
  }
1186
1169
 
1187
1170
  .say-pill {
1188
- gap: 0;
1189
1171
  vertical-align: bottom;
1190
1172
  min-height: 2.55rem;
1191
1173
  margin-bottom: -0.1rem;
@@ -1204,6 +1186,15 @@
1204
1186
  cursor: text;
1205
1187
  color: var(--au-blue-700);
1206
1188
  }
1189
+ .say-pill--error {
1190
+ color: var(--au-red-700);
1191
+ background-color: var(--au-red-200);
1192
+ border-color: var(--au-red-300);
1193
+ text-decoration-color: var(--au-red-300);
1194
+ }
1195
+ .say-pill--error [contenteditable] {
1196
+ color: var(--au-red-700);
1197
+ }
1207
1198
 
1208
1199
  .ember-node.ProseMirror-selectednode .say-pill {
1209
1200
  background-color: var(--au-blue-200);
@@ -1216,6 +1207,16 @@
1216
1207
  .ember-node.ProseMirror-selectednode .say-pill ::selection {
1217
1208
  background-color: var(--au-blue-300);
1218
1209
  }
1210
+ .ember-node.ProseMirror-selectednode .say-pill--error {
1211
+ background-color: var(--au-red-200);
1212
+ outline: 2px solid var(--au-red-500);
1213
+ }
1214
+ .ember-node.ProseMirror-selectednode .say-pill--error ::-moz-selection {
1215
+ background-color: var(--au-red-300);
1216
+ }
1217
+ .ember-node.ProseMirror-selectednode .say-pill--error ::selection {
1218
+ background-color: var(--au-red-300);
1219
+ }
1219
1220
 
1220
1221
  .say-placeholder {
1221
1222
  font-style: italic;
@@ -1376,6 +1377,7 @@ table.ProseMirror-selectednode,
1376
1377
  .say-table-tooltip {
1377
1378
  display: flex;
1378
1379
  flex-direction: column;
1380
+ box-shadow: 0 1px 3px rgba(33, 35, 38, 0.1), 0 4px 20px rgba(33, 35, 38, 0.035), 0 1px 1px rgba(33, 35, 38, 0.025);
1379
1381
  }
1380
1382
  .say-table-tooltip .color-selector__grid {
1381
1383
  padding: 0 12px;
@@ -1591,7 +1593,6 @@ span.ember-node {
1591
1593
  width: 0;
1592
1594
  top: 0;
1593
1595
  left: 0;
1594
- z-index: 1;
1595
1596
  }
1596
1597
  .say-editor .invisible.invisible--space::before {
1597
1598
  content: "·";