@astryxdesign/richtext 0.7.14 → 0.7.15-canary.g061b2fa

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.
@@ -3,7 +3,12 @@
3
3
  * Intentionally permissive on path/query so real-world URLs linkify.
4
4
  */
5
5
  export declare const URL_MATCHER: RegExp;
6
- /** Matches a bare email address for AutoLink (rendered as a `mailto:` link). */
6
+ /**
7
+ * Matches a bare email address for AutoLink (rendered as a `mailto:` link).
8
+ * An unquoted local part starts only at the text start, after whitespace, or
9
+ * after one of `<>()[]\,;:@"`. A quoted local part ends at the next quote or
10
+ * line break. Each run is read once, so matching time stays linear.
11
+ */
7
12
  export declare const EMAIL_MATCHER: RegExp;
8
13
  /**
9
14
  * Return a safe href for `url`, or `'about:blank'` if it can't be parsed or uses
@@ -1 +1 @@
1
- {"version":3,"file":"linkUtils.d.ts","sourceRoot":"","sources":["../src/linkUtils.ts"],"names":[],"mappings":"AAoCA;;;GAGG;AACH,eAAO,MAAM,WAAW,QAC0F,CAAC;AAEnH,gFAAgF;AAChF,eAAO,MAAM,aAAa,QAC4H,CAAC;AAOvJ;;;;;GAKG;AACH,wBAAgB,WAAW,CAAC,GAAG,EAAE,MAAM,GAAG,MAAM,CAc/C;AAED;;;;;GAKG;AACH,wBAAgB,WAAW,CAAC,GAAG,EAAE,MAAM,GAAG,OAAO,CAWhD"}
1
+ {"version":3,"file":"linkUtils.d.ts","sourceRoot":"","sources":["../src/linkUtils.ts"],"names":[],"mappings":"AAoCA;;;GAGG;AACH,eAAO,MAAM,WAAW,QAC0F,CAAC;AAEnH;;;;;GAKG;AACH,eAAO,MAAM,aAAa,QACyJ,CAAC;AAOpL;;;;;GAKG;AACH,wBAAgB,WAAW,CAAC,GAAG,EAAE,MAAM,GAAG,MAAM,CAc/C;AAED;;;;;GAKG;AACH,wBAAgB,WAAW,CAAC,GAAG,EAAE,MAAM,GAAG,OAAO,CAWhD"}
package/dist/linkUtils.js CHANGED
@@ -40,8 +40,13 @@ const HAS_SCHEME = /^[a-z][a-z0-9+.-]*:/i;
40
40
  */
41
41
  export const URL_MATCHER = /((https?:\/\/(www\.)?)|(www\.))[-a-zA-Z0-9@:%._+~#=]{1,256}\.[a-zA-Z0-9()]{1,6}\b([-a-zA-Z0-9()@:%_+.~#?&/=]*)/;
42
42
 
43
- /** Matches a bare email address for AutoLink (rendered as a `mailto:` link). */
44
- export const EMAIL_MATCHER = /(([^<>()[\]\\.,;:\s@"]+(\.[^<>()[\]\\.,;:\s@"]+)*)|(".+"))@((\[[0-9]{1,3}\.[0-9]{1,3}\.[0-9]{1,3}\.[0-9]{1,3}])|(([a-zA-Z\-0-9]+\.)+[a-zA-Z]{2,}))/;
43
+ /**
44
+ * Matches a bare email address for AutoLink (rendered as a `mailto:` link).
45
+ * An unquoted local part starts only at the text start, after whitespace, or
46
+ * after one of `<>()[]\,;:@"`. A quoted local part ends at the next quote or
47
+ * line break. Each run is read once, so matching time stays linear.
48
+ */
49
+ export const EMAIL_MATCHER = /((?<![^<>()[\]\\,;:\s@"])[^<>()[\]\\.,;:\s@"]+(\.[^<>()[\]\\.,;:\s@"]+)*|("[^"\r\n]+"))@((\[[0-9]{1,3}\.[0-9]{1,3}\.[0-9]{1,3}\.[0-9]{1,3}])|(([a-zA-Z\-0-9]+\.)+[a-zA-Z]{2,}))/;
45
50
 
46
51
  /** Prepend a default `https://` scheme to a bare host so it parses as absolute. */
47
52
  function withDefaultScheme(url) {
@@ -1 +1 @@
1
- {"version":3,"file":"markdownCharacterReferences.d.ts","sourceRoot":"","sources":["../src/markdownCharacterReferences.ts"],"names":[],"mappings":"AAiCA,OAAO,EAML,KAAK,WAAW,EAChB,KAAK,WAAW,EACjB,MAAM,SAAS,CAAC;AAMjB;;;GAGG;AACH,KAAK,OAAO,GACR;IAAC,QAAQ,CAAC,IAAI,EAAE,WAAW,CAAC;IAAC,QAAQ,CAAC,MAAM,EAAE,MAAM,CAAA;CAAC,GACrD;IAAC,QAAQ,CAAC,IAAI,EAAE,WAAW,CAAA;CAAC,GAC5B;IAAC,QAAQ,CAAC,IAAI,EAAE,QAAQ,CAAC;IAAC,QAAQ,CAAC,SAAS,EAAE,MAAM,CAAA;CAAC,GACrD;IAAC,QAAQ,CAAC,IAAI,EAAE,WAAW,CAAA;CAAC,GAC5B;IAAC,QAAQ,CAAC,IAAI,EAAE,SAAS,CAAC;IAAC,QAAQ,CAAC,IAAI,EAAE,MAAM,CAAA;CAAC,CAAC;AAEtD,MAAM,WAAW,iBAAiB;IAChC,wDAAwD;IACxD,QAAQ,CAAC,QAAQ,EAAE,MAAM,CAAC;IAC1B,mCAAmC;IACnC,QAAQ,CAAC,QAAQ,EAAE,WAAW,CAAC,MAAM,EAAE,OAAO,CAAC,CAAC;CACjD;AAYD,oEAAoE;AACpE,wBAAiB,gBAAgB,CAAC,IAAI,EAAE,MAAM,GAAG,SAAS,CAAC,MAAM,CAAC,CAUjE;AAkID;;;;;;;GAOG;AACH,wBAAgB,uBAAuB,CAAC,QAAQ,EAAE,MAAM,GAAG,iBAAiB,CA2D3E;AAkHD;;;;GAIG;AACH,wBAAgB,cAAc,CAAC,GAAG,EAAE,MAAM,GAAG,OAAO,CAUnD;AAED;;;;;;;;;;;;GAYG;AACH,wBAAgB,mBAAmB,CAAC,QAAQ,EAAE,MAAM,GAAG,iBAAiB,CA8DvE;AAUD,oEAAoE;AACpE,wBAAgB,cAAc,CAAC,IAAI,EAAE,WAAW,GAAG,OAAO,CAEzD;AAED;;;;;;;;;GASG;AACH,wBAAgB,aAAa,CAAC,QAAQ,EAAE,MAAM,GAAG;IAC/C,QAAQ,CAAC,QAAQ,EAAE,MAAM,CAAC;IAC1B,QAAQ,CAAC,MAAM,EAAE,WAAW,CAAC,MAAM,EAAE,MAAM,CAAC,CAAC;CAC9C,CA+DA;AAED;;;;;GAKG;AACH,wBAAgB,cAAc,CAC5B,IAAI,EAAE,WAAW,EACjB,MAAM,EAAE,WAAW,CAAC,MAAM,EAAE,MAAM,CAAC,GAClC,IAAI,CA8BN;AAED;;;;GAIG;AACH,wBAAgB,mBAAmB,CAAC,IAAI,EAAE,WAAW,GAAG,IAAI,CAS3D;AAED;;;;;;GAMG;AACH,wBAAgB,iCAAiC,CAC/C,QAAQ,EAAE,MAAM,GACf,iBAAiB,CA4EnB;AAED,qEAAqE;AACrE,MAAM,WAAW,kBAAkB;IACjC,QAAQ,CAAC,QAAQ,EAAE,MAAM,CAAC;IAC1B,QAAQ,CAAC,KAAK,EAAE,WAAW,CAAC,MAAM,EAAE,MAAM,CAAC,CAAC;IAC5C,+DAA+D;IAC/D,QAAQ,CAAC,QAAQ,EAAE,WAAW,CAAC,MAAM,EAAE,OAAO,CAAC,CAAC;CACjD;AA+ED;;;;;;;;;;;;GAYG;AACH,wBAAgB,gBAAgB,CAAC,QAAQ,EAAE,MAAM,GAAG,kBAAkB,CAwErE;AAED;;;;GAIG;AACH,wBAAgB,iBAAiB,CAC/B,IAAI,EAAE,WAAW,EACjB,KAAK,EAAE,WAAW,CAAC,MAAM,EAAE,MAAM,CAAC,GACjC,IAAI,CAgCN;AAED;;;;GAIG;AACH,wBAAgB,0BAA0B,CACxC,QAAQ,EAAE,MAAM,GACf,iBAAiB,CA+EnB;AAmDD;;;;;GAKG;AACH,wBAAgB,2BAA2B,CACzC,IAAI,EAAE,WAAW,EACjB,QAAQ,EAAE,WAAW,CAAC,MAAM,EAAE,OAAO,CAAC,GACrC,IAAI,CAsCN"}
1
+ {"version":3,"file":"markdownCharacterReferences.d.ts","sourceRoot":"","sources":["../src/markdownCharacterReferences.ts"],"names":[],"mappings":"AAiCA,OAAO,EAML,KAAK,WAAW,EAChB,KAAK,WAAW,EACjB,MAAM,SAAS,CAAC;AAMjB;;;GAGG;AACH,KAAK,OAAO,GACR;IAAC,QAAQ,CAAC,IAAI,EAAE,WAAW,CAAC;IAAC,QAAQ,CAAC,MAAM,EAAE,MAAM,CAAA;CAAC,GACrD;IAAC,QAAQ,CAAC,IAAI,EAAE,WAAW,CAAA;CAAC,GAC5B;IAAC,QAAQ,CAAC,IAAI,EAAE,QAAQ,CAAC;IAAC,QAAQ,CAAC,SAAS,EAAE,MAAM,CAAA;CAAC,GACrD;IAAC,QAAQ,CAAC,IAAI,EAAE,WAAW,CAAA;CAAC,GAC5B;IAAC,QAAQ,CAAC,IAAI,EAAE,SAAS,CAAC;IAAC,QAAQ,CAAC,IAAI,EAAE,MAAM,CAAA;CAAC,CAAC;AAEtD,MAAM,WAAW,iBAAiB;IAChC,wDAAwD;IACxD,QAAQ,CAAC,QAAQ,EAAE,MAAM,CAAC;IAC1B,mCAAmC;IACnC,QAAQ,CAAC,QAAQ,EAAE,WAAW,CAAC,MAAM,EAAE,OAAO,CAAC,CAAC;CACjD;AAYD,oEAAoE;AACpE,wBAAiB,gBAAgB,CAAC,IAAI,EAAE,MAAM,GAAG,SAAS,CAAC,MAAM,CAAC,CAUjE;AAkID;;;;;;;GAOG;AACH,wBAAgB,uBAAuB,CAAC,QAAQ,EAAE,MAAM,GAAG,iBAAiB,CA2D3E;AAkHD;;;;GAIG;AACH,wBAAgB,cAAc,CAAC,GAAG,EAAE,MAAM,GAAG,OAAO,CAUnD;AAED;;;;;;;;;;;;GAYG;AACH,wBAAgB,mBAAmB,CAAC,QAAQ,EAAE,MAAM,GAAG,iBAAiB,CA8DvE;AAUD,oEAAoE;AACpE,wBAAgB,cAAc,CAAC,IAAI,EAAE,WAAW,GAAG,OAAO,CAEzD;AAED;;;;;;;;;GASG;AACH,wBAAgB,aAAa,CAAC,QAAQ,EAAE,MAAM,GAAG;IAC/C,QAAQ,CAAC,QAAQ,EAAE,MAAM,CAAC;IAC1B,QAAQ,CAAC,MAAM,EAAE,WAAW,CAAC,MAAM,EAAE,MAAM,CAAC,CAAC;CAC9C,CA+DA;AAED;;;;;GAKG;AACH,wBAAgB,cAAc,CAC5B,IAAI,EAAE,WAAW,EACjB,MAAM,EAAE,WAAW,CAAC,MAAM,EAAE,MAAM,CAAC,GAClC,IAAI,CA8BN;AAED;;;;GAIG;AACH,wBAAgB,mBAAmB,CAAC,IAAI,EAAE,WAAW,GAAG,IAAI,CAS3D;AAED;;;;;;GAMG;AACH,wBAAgB,iCAAiC,CAC/C,QAAQ,EAAE,MAAM,GACf,iBAAiB,CA4EnB;AAED,qEAAqE;AACrE,MAAM,WAAW,kBAAkB;IACjC,QAAQ,CAAC,QAAQ,EAAE,MAAM,CAAC;IAC1B,QAAQ,CAAC,KAAK,EAAE,WAAW,CAAC,MAAM,EAAE,MAAM,CAAC,CAAC;IAC5C,+DAA+D;IAC/D,QAAQ,CAAC,QAAQ,EAAE,WAAW,CAAC,MAAM,EAAE,OAAO,CAAC,CAAC;CACjD;AA2FD;;;;;;;;;;;;GAYG;AACH,wBAAgB,gBAAgB,CAAC,QAAQ,EAAE,MAAM,GAAG,kBAAkB,CAwErE;AAED;;;;GAIG;AACH,wBAAgB,iBAAiB,CAC/B,IAAI,EAAE,WAAW,EACjB,KAAK,EAAE,WAAW,CAAC,MAAM,EAAE,MAAM,CAAC,GACjC,IAAI,CAgCN;AAED;;;;GAIG;AACH,wBAAgB,0BAA0B,CACxC,QAAQ,EAAE,MAAM,GACf,iBAAiB,CA+EnB;AAmDD;;;;;GAKG;AACH,wBAAgB,2BAA2B,CACzC,IAAI,EAAE,WAAW,EACjB,QAAQ,EAAE,WAAW,CAAC,MAAM,EAAE,OAAO,CAAC,GACrC,IAAI,CAsCN"}
@@ -741,8 +741,20 @@ function hasUnescapedPipe(text) {
741
741
  return false;
742
742
  }
743
743
 
744
- /** A GFM table's delimiter row: cells of hyphens with optional colons. */
745
- const TABLE_DELIMITER_ROW = /^\s*\|?\s*:?-+:?\s*(\|\s*:?-+:?\s*)*\|?\s*$/;
744
+ /**
745
+ * Test each cell on its own. One regex over the whole row backtracks in
746
+ * quadratic time on a long run of spaces.
747
+ */
748
+ function isTableDelimiterRow(line) {
749
+ let body = line.trim();
750
+ if (body.startsWith('|')) {
751
+ body = body.slice(1);
752
+ }
753
+ if (body.endsWith('|')) {
754
+ body = body.slice(0, -1);
755
+ }
756
+ return body.split('|').every(cell => /^:?-+:?$/.test(cell.trim()));
757
+ }
746
758
 
747
759
  /**
748
760
  * The ranges of `markdown` a code span must not start in: inline link
@@ -780,7 +792,7 @@ function tableRowRanges(markdown) {
780
792
  }
781
793
  for (let index = 1; index < lines.length; index++) {
782
794
  const line = lines[index];
783
- if (line.includes('|') && TABLE_DELIMITER_ROW.test(line) && lines[index - 1].includes('|')) {
795
+ if (line.includes('|') && isTableDelimiterRow(line) && lines[index - 1].includes('|')) {
784
796
  let end = index + 1;
785
797
  while (end < lines.length && lines[end].trim() !== '') {
786
798
  end++;
package/package.json CHANGED
@@ -1,7 +1,7 @@
1
1
  {
2
2
  "name": "@astryxdesign/richtext",
3
3
  "displayName": "Rich Text",
4
- "version": "0.7.14",
4
+ "version": "0.7.15-canary.g061b2fa",
5
5
  "description": "Astryx rich text — a Lexical-based rich text editor and viewer, styled with Astryx design tokens.",
6
6
  "author": "Meta Open Source",
7
7
  "license": "MIT",
@@ -66,7 +66,7 @@
66
66
  },
67
67
  "peerDependencies": {
68
68
  "@stylexjs/stylex": ">=0.10.0",
69
- "@astryxdesign/core": "0.7.14",
69
+ "@astryxdesign/core": "0.7.15-canary.g061b2fa",
70
70
  "react": ">=19.0.0",
71
71
  "react-dom": ">=19.0.0",
72
72
  "lexical": "^0.52.0",
@@ -125,6 +125,8 @@
125
125
  }
126
126
  },
127
127
  "devDependencies": {
128
+ "@astryxdesign/a11y-spec": "0.7.15-canary.g061b2fa",
129
+ "@astryxdesign/cli": "0.7.15-canary.g061b2fa",
128
130
  "@babel/cli": "^7.29.7",
129
131
  "@babel/core": "^7.29.7",
130
132
  "@babel/preset-react": "^7.29.7",
@@ -143,9 +145,7 @@
143
145
  "@lexical/utils": "^0.52.0",
144
146
  "@stylexjs/babel-plugin": "^0.19.1",
145
147
  "@testing-library/react": "^16.3.3",
146
- "lexical": "^0.52.0",
147
- "@astryxdesign/a11y-spec": "0.0.0",
148
- "@astryxdesign/cli": "0.7.14"
148
+ "lexical": "^0.52.0"
149
149
  },
150
150
  "scripts": {
151
151
  "build": "node ../../scripts/clean-dist.mjs && pnpm build:esm && tsc --project tsconfig.build.json && node ../../scripts/add-declaration-extensions.mjs && pnpm build:css && node ../../scripts/check-no-dev-jsx.mjs && node ../../scripts/check-fully-specified.mjs",
package/src/linkUtils.ts CHANGED
@@ -41,9 +41,14 @@ const HAS_SCHEME = /^[a-z][a-z0-9+.-]*:/i;
41
41
  export const URL_MATCHER =
42
42
  /((https?:\/\/(www\.)?)|(www\.))[-a-zA-Z0-9@:%._+~#=]{1,256}\.[a-zA-Z0-9()]{1,6}\b([-a-zA-Z0-9()@:%_+.~#?&/=]*)/;
43
43
 
44
- /** Matches a bare email address for AutoLink (rendered as a `mailto:` link). */
44
+ /**
45
+ * Matches a bare email address for AutoLink (rendered as a `mailto:` link).
46
+ * An unquoted local part starts only at the text start, after whitespace, or
47
+ * after one of `<>()[]\,;:@"`. A quoted local part ends at the next quote or
48
+ * line break. Each run is read once, so matching time stays linear.
49
+ */
45
50
  export const EMAIL_MATCHER =
46
- /(([^<>()[\]\\.,;:\s@"]+(\.[^<>()[\]\\.,;:\s@"]+)*)|(".+"))@((\[[0-9]{1,3}\.[0-9]{1,3}\.[0-9]{1,3}\.[0-9]{1,3}])|(([a-zA-Z\-0-9]+\.)+[a-zA-Z]{2,}))/;
51
+ /((?<![^<>()[\]\\,;:\s@"])[^<>()[\]\\.,;:\s@"]+(\.[^<>()[\]\\.,;:\s@"]+)*|("[^"\r\n]+"))@((\[[0-9]{1,3}\.[0-9]{1,3}\.[0-9]{1,3}\.[0-9]{1,3}])|(([a-zA-Z\-0-9]+\.)+[a-zA-Z]{2,}))/;
47
52
 
48
53
  /** Prepend a default `https://` scheme to a bare host so it parses as absolute. */
49
54
  function withDefaultScheme(url: string): string {
@@ -747,8 +747,20 @@ function hasUnescapedPipe(text: string): boolean {
747
747
  return false;
748
748
  }
749
749
 
750
- /** A GFM table's delimiter row: cells of hyphens with optional colons. */
751
- const TABLE_DELIMITER_ROW = /^\s*\|?\s*:?-+:?\s*(\|\s*:?-+:?\s*)*\|?\s*$/;
750
+ /**
751
+ * Test each cell on its own. One regex over the whole row backtracks in
752
+ * quadratic time on a long run of spaces.
753
+ */
754
+ function isTableDelimiterRow(line: string): boolean {
755
+ let body = line.trim();
756
+ if (body.startsWith('|')) {
757
+ body = body.slice(1);
758
+ }
759
+ if (body.endsWith('|')) {
760
+ body = body.slice(0, -1);
761
+ }
762
+ return body.split('|').every(cell => /^:?-+:?$/.test(cell.trim()));
763
+ }
752
764
 
753
765
  /**
754
766
  * The ranges of `markdown` a code span must not start in: inline link
@@ -795,7 +807,7 @@ function tableRowRanges(markdown: string): Array<readonly [number, number]> {
795
807
  const line = lines[index];
796
808
  if (
797
809
  line.includes('|') &&
798
- TABLE_DELIMITER_ROW.test(line) &&
810
+ isTableDelimiterRow(line) &&
799
811
  lines[index - 1].includes('|')
800
812
  ) {
801
813
  let end = index + 1;