@ni/nimble-components 20.14.7 → 20.14.9

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 (31) hide show
  1. package/dist/all-components-bundle.js +244 -14
  2. package/dist/all-components-bundle.js.map +1 -1
  3. package/dist/all-components-bundle.min.js +1059 -1035
  4. package/dist/all-components-bundle.min.js.map +1 -1
  5. package/dist/esm/number-field/index.js +2 -0
  6. package/dist/esm/number-field/index.js.map +1 -1
  7. package/dist/esm/rich-text/models/markdown-parser-mention-configuration.d.ts +15 -0
  8. package/dist/esm/rich-text/models/markdown-parser-mention-configuration.js +26 -0
  9. package/dist/esm/rich-text/models/markdown-parser-mention-configuration.js.map +1 -0
  10. package/dist/esm/rich-text/models/markdown-parser.d.ts +9 -2
  11. package/dist/esm/rich-text/models/markdown-parser.js +34 -9
  12. package/dist/esm/rich-text/models/markdown-parser.js.map +1 -1
  13. package/dist/esm/rich-text/models/testing/markdown-parser-utils.d.ts +1 -0
  14. package/dist/esm/rich-text/models/testing/markdown-parser-utils.js +3 -0
  15. package/dist/esm/rich-text/models/testing/markdown-parser-utils.js.map +1 -1
  16. package/dist/esm/rich-text/viewer/index.d.ts +24 -0
  17. package/dist/esm/rich-text/viewer/index.js +66 -4
  18. package/dist/esm/rich-text/viewer/index.js.map +1 -1
  19. package/dist/esm/rich-text/viewer/styles.js +14 -1
  20. package/dist/esm/rich-text/viewer/styles.js.map +1 -1
  21. package/dist/esm/rich-text/viewer/template.js +4 -2
  22. package/dist/esm/rich-text/viewer/template.js.map +1 -1
  23. package/dist/esm/rich-text/viewer/testing/rich-text-viewer.pageobject.d.ts +1 -0
  24. package/dist/esm/rich-text/viewer/testing/rich-text-viewer.pageobject.js +6 -3
  25. package/dist/esm/rich-text/viewer/testing/rich-text-viewer.pageobject.js.map +1 -1
  26. package/dist/esm/rich-text-mention/base/models/mention-internals.d.ts +5 -0
  27. package/dist/esm/rich-text-mention/base/models/mention-internals.js +1 -0
  28. package/dist/esm/rich-text-mention/base/models/mention-internals.js.map +1 -1
  29. package/dist/esm/rich-text-mention/users/index.js +3 -1
  30. package/dist/esm/rich-text-mention/users/index.js.map +1 -1
  31. package/package.json +1 -1
@@ -16298,7 +16298,7 @@
16298
16298
 
16299
16299
  /**
16300
16300
  * Do not edit directly
16301
- * Generated on Tue, 21 Nov 2023 16:47:41 GMT
16301
+ * Generated on Thu, 23 Nov 2023 07:56:58 GMT
16302
16302
  */
16303
16303
 
16304
16304
  const Information100DarkUi = "#a46eff";
@@ -24911,6 +24911,7 @@
24911
24911
  appearance="ghost"
24912
24912
  content-hidden
24913
24913
  tabindex="-1"
24914
+ aria-hidden="true"
24914
24915
  >
24915
24916
  ${x => numericDecrementLabel.getValueFor(x)}
24916
24917
  <${iconMinusWideTag}
@@ -24925,6 +24926,7 @@
24925
24926
  appearance="ghost"
24926
24927
  content-hidden
24927
24928
  tabindex="-1"
24929
+ aria-hidden="true"
24928
24930
  >
24929
24931
  ${x => numericIncrementLabel.getValueFor(x)}
24930
24932
  <${iconAddTag}
@@ -58805,12 +58807,18 @@ img.ProseMirror-separator {
58805
58807
  * DOM structure using a DOMSerializer, and returns the serialized result.
58806
58808
  * If the markdown parser returns null, it will clear the viewer component by creating an empty document fragment.
58807
58809
  */
58808
- static parseMarkdownToDOM(value) {
58809
- const parsedMarkdownContent = this.markdownParser.parse(value);
58810
- if (parsedMarkdownContent === null) {
58811
- return document.createDocumentFragment();
58810
+ static parseMarkdownToDOM(value, markdownParserMentionConfig) {
58811
+ try {
58812
+ this.mentionConfigs = markdownParserMentionConfig;
58813
+ const parsedMarkdownContent = this.markdownParser.parse(value);
58814
+ if (parsedMarkdownContent === null) {
58815
+ return document.createDocumentFragment();
58816
+ }
58817
+ return this.domSerializer.serializeFragment(parsedMarkdownContent.content);
58818
+ }
58819
+ finally {
58820
+ this.mentionConfigs = undefined;
58812
58821
  }
58813
- return this.domSerializer.serializeFragment(parsedMarkdownContent.content);
58814
58822
  }
58815
58823
  static initializeMarkdownParser() {
58816
58824
  /**
@@ -58829,7 +58837,6 @@ img.ProseMirror-separator {
58829
58837
  'autolink',
58830
58838
  'newline'
58831
58839
  ]);
58832
- supportedTokenizerRules.validateLink = href => /^https?:\/\//i.test(href);
58833
58840
  /**
58834
58841
  * In order to display encoded characters, non-ASCII characters, emojis, and other special characters in their original form,
58835
58842
  * we bypass the default normalization of link text in markdown-it. This is done because we support only "AutoLink" feature in CommonMark flavor.
@@ -58841,7 +58848,7 @@ img.ProseMirror-separator {
58841
58848
  supportedTokenizerRules.normalizeLinkText = url => url;
58842
58849
  return new MarkdownParser(this.updatedSchema, supportedTokenizerRules, defaultMarkdownParser.tokens);
58843
58850
  }
58844
- static getSchemaWithLinkConfiguration() {
58851
+ static getCustomSchemaConfiguration() {
58845
58852
  return new Schema({
58846
58853
  nodes: schema.spec.nodes,
58847
58854
  marks: {
@@ -58857,10 +58864,30 @@ img.ProseMirror-separator {
58857
58864
  // See: https://github.com/ni/nimble/issues/1527
58858
58865
  excludes: '_',
58859
58866
  toDOM(node) {
58867
+ const href = node.attrs.href;
58868
+ const currentMention = RichTextMarkdownParser.mentionConfigs?.find(mention => mention.isValidMentionHref(href));
58869
+ const displayName = currentMention?.getDisplayName(href);
58870
+ if (currentMention && displayName) {
58871
+ return [
58872
+ currentMention.viewElement,
58873
+ {
58874
+ 'mention-href': href,
58875
+ 'mention-label': displayName,
58876
+ 'disable-editing': true
58877
+ }
58878
+ ];
58879
+ }
58860
58880
  return [
58861
58881
  anchorTag,
58862
58882
  {
58863
- href: node.attrs.href,
58883
+ /**
58884
+ * Both mention and absolute link markdown share the autolink format in CommonMark flavor.
58885
+ * Absolute links with HTTP/HTTPS will be rendered as links. Absolute links that match the
58886
+ * mention pattern will be rendered as mention view element. Absolute links without HTTP/HTTPS
58887
+ * scheme and no matching mention pattern will be rendered as plain text (anchor with no href).
58888
+ * With this, the user can click the links only when the scheme is HTTP/HTTPS
58889
+ */
58890
+ href: /^https?:\/\//i.test(href) ? href : null,
58864
58891
  rel: node.attrs.rel
58865
58892
  }
58866
58893
  ];
@@ -58873,7 +58900,7 @@ img.ProseMirror-separator {
58873
58900
  }
58874
58901
  }
58875
58902
  _a$1 = RichTextMarkdownParser;
58876
- RichTextMarkdownParser.updatedSchema = _a$1.getSchemaWithLinkConfiguration();
58903
+ RichTextMarkdownParser.updatedSchema = _a$1.getCustomSchemaConfiguration();
58877
58904
  RichTextMarkdownParser.markdownParser = _a$1.initializeMarkdownParser();
58878
58905
  RichTextMarkdownParser.domSerializer = DOMSerializer.fromSchema(_a$1.updatedSchema);
58879
58906
 
@@ -59443,7 +59470,9 @@ img.ProseMirror-separator {
59443
59470
  DesignSystem.tagFor(RichTextEditor);
59444
59471
 
59445
59472
  const template$k = html `
59446
- <div ${ref('viewer')} class="viewer"></div>
59473
+ <template ${children$1({ property: 'childItems', filter: elements() })}>
59474
+ <div ${ref('viewer')} class="viewer"></div>
59475
+ </template>
59447
59476
  `;
59448
59477
 
59449
59478
  const styles$o = css `
@@ -59484,8 +59513,150 @@ img.ProseMirror-separator {
59484
59513
  li > p:empty {
59485
59514
  display: none;
59486
59515
  }
59516
+
59517
+ ${
59518
+ /**
59519
+ * When an absolute link is not HTTPS/HTTP, the anchor tag renders without an `href`, appearing as plain text.
59520
+ * However, the `nimble-anchor` displays differently in color when the `href` attribute is absent.
59521
+ * To ensure a consistent appearance, the font color is forced to the default link color regardless of the `href`
59522
+ * attribute's presence.
59523
+ *
59524
+ * See models/markdown-parser.ts where link elements are emitted for more info.
59525
+ */ ''}
59526
+ nimble-anchor::part(control) {
59527
+ color: ${linkFontColor};
59528
+ }
59487
59529
  `;
59488
59530
 
59531
+ /**
59532
+ * Internal mention state
59533
+ */
59534
+ class MentionInternals {
59535
+ constructor(options) {
59536
+ /**
59537
+ * Whether this mention has a valid configuration.
59538
+ */
59539
+ this.validConfiguration = true;
59540
+ this.icon = options.icon;
59541
+ this.character = options.character;
59542
+ this.viewElement = options.viewElement;
59543
+ }
59544
+ }
59545
+ __decorate$1([
59546
+ observable
59547
+ ], MentionInternals.prototype, "mentionConfig", void 0);
59548
+ __decorate$1([
59549
+ observable
59550
+ ], MentionInternals.prototype, "validConfiguration", void 0);
59551
+
59552
+ /**
59553
+ * The base class for Mention configuration
59554
+ */
59555
+ class RichTextMention extends FoundationElement {
59556
+ constructor() {
59557
+ super(...arguments);
59558
+ /**
59559
+ * @internal
59560
+ */
59561
+ this.mentionInternals = new MentionInternals(this.getMentionInternalsOptions());
59562
+ /** @internal */
59563
+ this.validator = this.createValidator();
59564
+ /** @internal */
59565
+ this.mappingNotifiers = [];
59566
+ /** @internal */
59567
+ this.mappings = [];
59568
+ }
59569
+ checkValidity() {
59570
+ return this.mentionInternals.validConfiguration;
59571
+ }
59572
+ get validity() {
59573
+ return this.validator.getValidity();
59574
+ }
59575
+ /**
59576
+ * @internal
59577
+ */
59578
+ handleChange(source, args) {
59579
+ if (source instanceof Mapping$1 && typeof args === 'string') {
59580
+ this.updateMentionConfig();
59581
+ }
59582
+ }
59583
+ getMappingConfigs() {
59584
+ const mappingConfigs = new Map();
59585
+ this.mappings.forEach(mapping => {
59586
+ const href = mapping.key ?? undefined;
59587
+ if (href === undefined || typeof href !== 'string') {
59588
+ throw Error('mentionHref was invalid for type. Validation should have prevented this.');
59589
+ }
59590
+ const mappingConfig = this.createMappingConfig(mapping);
59591
+ mappingConfigs.set(href, mappingConfig);
59592
+ });
59593
+ return mappingConfigs;
59594
+ }
59595
+ /**
59596
+ * Called when any Mapping related state has changed.
59597
+ */
59598
+ updateMentionConfig() {
59599
+ this.validator.validate(this.mappings, this.pattern);
59600
+ this.mentionInternals.mentionConfig = this.validator.isValid()
59601
+ ? this.createMentionConfig(this.getMappingConfigs())
59602
+ : undefined;
59603
+ }
59604
+ mappingsChanged() {
59605
+ this.updateMentionConfig();
59606
+ this.observeMappings();
59607
+ }
59608
+ patternChanged() {
59609
+ this.mentionInternals.pattern = this.pattern;
59610
+ this.updateMentionConfig();
59611
+ }
59612
+ removeMappingObservers() {
59613
+ this.mappingNotifiers.forEach(notifier => {
59614
+ notifier.unsubscribe(this);
59615
+ });
59616
+ this.mappingNotifiers = [];
59617
+ }
59618
+ observeMappings() {
59619
+ this.removeMappingObservers();
59620
+ for (const mapping of this.mappings) {
59621
+ const notifier = Observable.getNotifier(mapping);
59622
+ notifier.subscribe(this);
59623
+ this.mappingNotifiers.push(notifier);
59624
+ }
59625
+ }
59626
+ }
59627
+ __decorate$1([
59628
+ attr
59629
+ ], RichTextMention.prototype, "pattern", void 0);
59630
+ __decorate$1([
59631
+ observable
59632
+ ], RichTextMention.prototype, "mappings", void 0);
59633
+
59634
+ /**
59635
+ * A configuration object for a Markdown parser, to be used by the viewer and editor components.
59636
+ * This object maintains the necessary internal values for handling mentions within the Markdown parser.
59637
+ */
59638
+ class MarkdownParserMentionConfiguration {
59639
+ constructor(mentionInternals) {
59640
+ this.regexPattern = new RegExp(mentionInternals.pattern ?? '');
59641
+ this.mappingConfigs = mentionInternals.mentionConfig?.mappingConfigs;
59642
+ this.viewElement = mentionInternals.viewElement;
59643
+ }
59644
+ isValidMentionHref(mentionHref) {
59645
+ return this.regexPattern.test(mentionHref);
59646
+ }
59647
+ getDisplayName(mentionHref) {
59648
+ const mentionMapping = this.mappingConfigs?.get(mentionHref);
59649
+ const mentionId = this.extractMentionId(mentionHref);
59650
+ return mentionMapping?.displayName ?? mentionId;
59651
+ }
59652
+ extractMentionId(mentionHref) {
59653
+ const regexpArray = this.regexPattern.exec(mentionHref);
59654
+ // Matches and gets the first group specified in the regex pattern
59655
+ // that renders as an alternative to the display name if missing.
59656
+ return regexpArray?.[1] ?? undefined;
59657
+ }
59658
+ }
59659
+
59489
59660
  /**
59490
59661
  * A nimble styled rich text viewer
59491
59662
  */
@@ -59498,6 +59669,19 @@ img.ProseMirror-separator {
59498
59669
  * Markdown string to render its corresponding rich text content in the component.
59499
59670
  */
59500
59671
  this.markdown = '';
59672
+ /**
59673
+ * @internal
59674
+ */
59675
+ this.mentionElements = [];
59676
+ /**
59677
+ * @internal
59678
+ */
59679
+ this.mentionInternalsConfig = [];
59680
+ /**
59681
+ * @internal
59682
+ */
59683
+ this.childItems = [];
59684
+ this.mentionInternalsNotifiers = [];
59501
59685
  }
59502
59686
  /**
59503
59687
  * @internal
@@ -59510,13 +59694,56 @@ img.ProseMirror-separator {
59510
59694
  * @internal
59511
59695
  */
59512
59696
  markdownChanged() {
59513
- if (this.$fastController.isConnected) {
59514
- this.updateView();
59697
+ this.updateView();
59698
+ }
59699
+ /**
59700
+ * @internal
59701
+ */
59702
+ handleChange(source, args) {
59703
+ if (source instanceof MentionInternals && typeof args === 'string') {
59704
+ this.updateMentionInternalsConfig();
59515
59705
  }
59516
59706
  }
59707
+ childItemsChanged() {
59708
+ void this.updateMentionsFromChildItems();
59709
+ }
59710
+ async updateMentionsFromChildItems() {
59711
+ const definedElements = this.childItems.map(async (item) => (item.matches(':not(:defined)')
59712
+ ? customElements.whenDefined(item.localName)
59713
+ : Promise.resolve()));
59714
+ await Promise.all(definedElements);
59715
+ this.mentionElements = this.childItems.filter((x) => x instanceof RichTextMention);
59716
+ this.observeMentions();
59717
+ this.updateMentionInternalsConfig();
59718
+ }
59719
+ observeMentions() {
59720
+ this.removeMentionObservers();
59721
+ for (const mention of this.mentionElements) {
59722
+ const notifierInternals = Observable.getNotifier(mention.mentionInternals);
59723
+ notifierInternals.subscribe(this);
59724
+ this.mentionInternalsNotifiers.push(notifierInternals);
59725
+ }
59726
+ }
59727
+ removeMentionObservers() {
59728
+ this.mentionInternalsNotifiers.forEach(notifier => {
59729
+ notifier.unsubscribe(this);
59730
+ });
59731
+ this.mentionInternalsNotifiers = [];
59732
+ }
59733
+ updateMentionInternalsConfig() {
59734
+ // TODO: Add a rich text validator to check if the `mentionElements` contains duplicate configuration element
59735
+ // For example, having two `nimble-rich-text-mention-users` within the children of rich text viewer or editor is an invalid configuration
59736
+ this.mentionInternalsConfig = this.mentionElements
59737
+ .filter(mention => mention.mentionInternals.validConfiguration)
59738
+ .map(mention => new MarkdownParserMentionConfiguration(mention.mentionInternals));
59739
+ this.updateView();
59740
+ }
59517
59741
  updateView() {
59742
+ if (!this.$fastController.isConnected) {
59743
+ return;
59744
+ }
59518
59745
  if (this.markdown) {
59519
- const serializedContent = RichTextMarkdownParser.parseMarkdownToDOM(this.markdown);
59746
+ const serializedContent = RichTextMarkdownParser.parseMarkdownToDOM(this.markdown, this.mentionInternalsConfig);
59520
59747
  this.viewer.replaceChildren(serializedContent);
59521
59748
  }
59522
59749
  else {
@@ -59527,6 +59754,9 @@ img.ProseMirror-separator {
59527
59754
  __decorate$1([
59528
59755
  observable
59529
59756
  ], RichTextViewer.prototype, "markdown", void 0);
59757
+ __decorate$1([
59758
+ observable
59759
+ ], RichTextViewer.prototype, "childItems", void 0);
59530
59760
  const nimbleRichTextViewer = RichTextViewer.compose({
59531
59761
  baseName: 'rich-text-viewer',
59532
59762
  template: template$k,