@dbcdk/react-components 0.0.194 → 0.0.195

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.
@@ -11,6 +11,7 @@ var JsonNode = require('./JsonNode');
11
11
  var styles = require('./JsonViewer.module.css');
12
12
  var useClipboardStatus = require('./useClipboardStatus');
13
13
  var utils = require('./utils');
14
+ var clipboard_utils = require('../../utils/clipboard.utils');
14
15
  var Button = require('../button/Button');
15
16
  var Icon = require('../icon/Icon');
16
17
 
@@ -83,12 +84,8 @@ function JsonViewer({
83
84
  deleted ? styles__default.default.deleted : ""
84
85
  ].filter(Boolean).join(" ");
85
86
  const handleCopy = async (nodeId, rawValue) => {
86
- try {
87
- await navigator.clipboard.writeText(rawValue);
88
- setCopiedId(nodeId);
89
- } catch {
90
- setCopiedId(null);
91
- }
87
+ const success = await clipboard_utils.copyToClipboard(rawValue);
88
+ setCopiedId(success ? nodeId : null);
92
89
  };
93
90
  const handleCopyAll = () => handleCopy(COPY_ALL_ID, rawJson);
94
91
  const handleExpandAll = () => {
@@ -9,6 +9,7 @@ import { JsonNode } from './JsonNode';
9
9
  import styles from './JsonViewer.module.css';
10
10
  import { useClipboardStatus } from './useClipboardStatus';
11
11
  import { normalizeSearch, isJsonValue, collectSearchMatches, collectExpandableNodeIds, collectInitiallyExpandedNodeIds } from './utils';
12
+ import { copyToClipboard } from '../../utils/clipboard.utils';
12
13
  import { Button } from '../button/Button';
13
14
  import { Icon } from '../icon/Icon';
14
15
 
@@ -77,12 +78,8 @@ function JsonViewer({
77
78
  deleted ? styles.deleted : ""
78
79
  ].filter(Boolean).join(" ");
79
80
  const handleCopy = async (nodeId, rawValue) => {
80
- try {
81
- await navigator.clipboard.writeText(rawValue);
82
- setCopiedId(nodeId);
83
- } catch {
84
- setCopiedId(null);
85
- }
81
+ const success = await copyToClipboard(rawValue);
82
+ setCopiedId(success ? nodeId : null);
86
83
  };
87
84
  const handleCopyAll = () => handleCopy(COPY_ALL_ID, rawJson);
88
85
  const handleExpandAll = () => {
@@ -9,6 +9,7 @@ var Popover = require('../../components/popover/Popover');
9
9
  var usePersistentState = require('../../hooks/usePersistentState');
10
10
  var styles = require('./LineViewer.module.css');
11
11
  var tokenizeLineFormat = require('./tokenizeLineFormat');
12
+ var clipboard_utils = require('../../utils/clipboard.utils');
12
13
  var Button = require('../button/Button');
13
14
  var Icon = require('../icon/Icon');
14
15
 
@@ -53,9 +54,7 @@ function LineViewer({
53
54
  validate: (stored) => typeof stored === "boolean"
54
55
  });
55
56
  const handleCopy = () => {
56
- var _a;
57
- (_a = navigator.clipboard) == null ? void 0 : _a.writeText(lines).catch(() => {
58
- });
57
+ void clipboard_utils.copyToClipboard(lines);
59
58
  };
60
59
  const handleDoubleClick = () => {
61
60
  const el = codeRef.current;
@@ -7,6 +7,7 @@ import { Popover } from '../../components/popover/Popover';
7
7
  import { usePersistentState } from '../../hooks/usePersistentState';
8
8
  import styles from './LineViewer.module.css';
9
9
  import { tokenizeLineFormat } from './tokenizeLineFormat';
10
+ import { copyToClipboard } from '../../utils/clipboard.utils';
10
11
  import { Button } from '../button/Button';
11
12
  import { Icon } from '../icon/Icon';
12
13
 
@@ -47,9 +48,7 @@ function LineViewer({
47
48
  validate: (stored) => typeof stored === "boolean"
48
49
  });
49
50
  const handleCopy = () => {
50
- var _a;
51
- (_a = navigator.clipboard) == null ? void 0 : _a.writeText(lines).catch(() => {
52
- });
51
+ void copyToClipboard(lines);
53
52
  };
54
53
  const handleDoubleClick = () => {
55
54
  const el = codeRef.current;
@@ -1,34 +1,51 @@
1
1
  'use strict';
2
2
 
3
- const FIELD_LINE_PATTERN = /^(\S+)(\s+)(\S+)(\s+)(\*[\s\S]*)$/;
3
+ const FIELD_LINE_PATTERN = /^(\d{3})(\s+)(?:((?!\*)\S+)(\s+))?(\*[\s\S]*)$/;
4
4
  const SUBFIELD_PATTERN = /\*(\S)([^*]*)/g;
5
+ function tokenizeSubfields(text) {
6
+ const tokens = [];
7
+ SUBFIELD_PATTERN.lastIndex = 0;
8
+ let match;
9
+ let lastIndex = 0;
10
+ while (match = SUBFIELD_PATTERN.exec(text)) {
11
+ if (match.index > lastIndex) {
12
+ tokens.push({ type: "text", value: text.slice(lastIndex, match.index) });
13
+ }
14
+ tokens.push({ type: "subfieldMarker", value: "*" });
15
+ tokens.push({ type: "subfieldCode", value: match[1] });
16
+ tokens.push({ type: "value", value: match[2] });
17
+ lastIndex = SUBFIELD_PATTERN.lastIndex;
18
+ }
19
+ if (lastIndex < text.length) {
20
+ tokens.push({ type: "text", value: text.slice(lastIndex) });
21
+ }
22
+ return tokens;
23
+ }
24
+ function tokenizeContinuationLine(line, continuesValue) {
25
+ const tokens = tokenizeSubfields(line);
26
+ if (!continuesValue) return tokens;
27
+ return tokens.map((token) => token.type === "text" ? { ...token, type: "value" } : token);
28
+ }
5
29
  function tokenizeFieldLine(line) {
6
30
  const match = FIELD_LINE_PATTERN.exec(line);
7
- if (!match) return [{ type: "text", value: line }];
31
+ if (!match) return tokenizeContinuationLine(line, false);
8
32
  const [, tag, gap1, indicator, gap2, rest] = match;
9
33
  const tokens = [
10
34
  { type: "tag", value: tag },
11
- { type: "whitespace", value: gap1 },
12
- { type: "indicator", value: indicator },
13
- { type: "whitespace", value: gap2 }
35
+ { type: "whitespace", value: gap1 }
14
36
  ];
15
- SUBFIELD_PATTERN.lastIndex = 0;
16
- let match2;
17
- let lastIndex = 0;
18
- while (match2 = SUBFIELD_PATTERN.exec(rest)) {
19
- tokens.push({ type: "subfieldMarker", value: "*" });
20
- tokens.push({ type: "subfieldCode", value: match2[1] });
21
- tokens.push({ type: "value", value: match2[2] });
22
- lastIndex = SUBFIELD_PATTERN.lastIndex;
23
- }
24
- if (lastIndex < rest.length) {
25
- tokens.push({ type: "text", value: rest.slice(lastIndex) });
37
+ if (indicator !== void 0) {
38
+ tokens.push({ type: "indicator", value: indicator });
39
+ tokens.push({ type: "whitespace", value: gap2 });
26
40
  }
41
+ tokens.push(...tokenizeSubfields(rest));
27
42
  return tokens;
28
43
  }
29
44
  function tokenizeLineFormat(source) {
45
+ var _a;
30
46
  const tokens = [];
31
47
  const chunks = source.split(/(\n)/);
48
+ let continuesValue = false;
32
49
  for (const chunk of chunks) {
33
50
  if (chunk === "") continue;
34
51
  if (chunk === "\n") {
@@ -42,9 +59,12 @@ function tokenizeLineFormat(source) {
42
59
  if (leading) tokens.push({ type: "text", value: leading });
43
60
  tokens.push({ type: "terminator", value: "$" });
44
61
  if (trailing) tokens.push({ type: "text", value: trailing });
62
+ continuesValue = false;
45
63
  continue;
46
64
  }
47
- tokens.push(...tokenizeFieldLine(chunk));
65
+ const lineTokens = FIELD_LINE_PATTERN.test(chunk) ? tokenizeFieldLine(chunk) : tokenizeContinuationLine(chunk, continuesValue);
66
+ tokens.push(...lineTokens);
67
+ continuesValue = ((_a = lineTokens[lineTokens.length - 1]) == null ? void 0 : _a.type) === "value";
48
68
  }
49
69
  return tokens;
50
70
  }
@@ -4,11 +4,12 @@ export interface LineToken {
4
4
  value: string;
5
5
  }
6
6
  /**
7
- * Tokenizes a MARC-style "line format" record (field tag, indicators,
8
- * `*code value` subfields, terminated by a lone `$`) for syntax
7
+ * Tokenizes a MARC-style "line format" record (field tag, optional
8
+ * indicators, `*code value` subfields, terminated by a lone `$`) for syntax
9
9
  * highlighting without imposing a strict grammar. Preserves the source
10
10
  * exactly - concatenating every token's `value` reproduces the input - so a
11
- * wrapped continuation line or malformed field still displays as plain
12
- * text instead of breaking the tokenizer.
11
+ * wrapped continuation after a subfield value retains value styling, while a
12
+ * standalone malformed line displays as plain text instead of breaking the
13
+ * tokenizer.
13
14
  */
14
15
  export declare function tokenizeLineFormat(source: string): LineToken[];
@@ -1,32 +1,49 @@
1
- const FIELD_LINE_PATTERN = /^(\S+)(\s+)(\S+)(\s+)(\*[\s\S]*)$/;
1
+ const FIELD_LINE_PATTERN = /^(\d{3})(\s+)(?:((?!\*)\S+)(\s+))?(\*[\s\S]*)$/;
2
2
  const SUBFIELD_PATTERN = /\*(\S)([^*]*)/g;
3
+ function tokenizeSubfields(text) {
4
+ const tokens = [];
5
+ SUBFIELD_PATTERN.lastIndex = 0;
6
+ let match;
7
+ let lastIndex = 0;
8
+ while (match = SUBFIELD_PATTERN.exec(text)) {
9
+ if (match.index > lastIndex) {
10
+ tokens.push({ type: "text", value: text.slice(lastIndex, match.index) });
11
+ }
12
+ tokens.push({ type: "subfieldMarker", value: "*" });
13
+ tokens.push({ type: "subfieldCode", value: match[1] });
14
+ tokens.push({ type: "value", value: match[2] });
15
+ lastIndex = SUBFIELD_PATTERN.lastIndex;
16
+ }
17
+ if (lastIndex < text.length) {
18
+ tokens.push({ type: "text", value: text.slice(lastIndex) });
19
+ }
20
+ return tokens;
21
+ }
22
+ function tokenizeContinuationLine(line, continuesValue) {
23
+ const tokens = tokenizeSubfields(line);
24
+ if (!continuesValue) return tokens;
25
+ return tokens.map((token) => token.type === "text" ? { ...token, type: "value" } : token);
26
+ }
3
27
  function tokenizeFieldLine(line) {
4
28
  const match = FIELD_LINE_PATTERN.exec(line);
5
- if (!match) return [{ type: "text", value: line }];
29
+ if (!match) return tokenizeContinuationLine(line, false);
6
30
  const [, tag, gap1, indicator, gap2, rest] = match;
7
31
  const tokens = [
8
32
  { type: "tag", value: tag },
9
- { type: "whitespace", value: gap1 },
10
- { type: "indicator", value: indicator },
11
- { type: "whitespace", value: gap2 }
33
+ { type: "whitespace", value: gap1 }
12
34
  ];
13
- SUBFIELD_PATTERN.lastIndex = 0;
14
- let match2;
15
- let lastIndex = 0;
16
- while (match2 = SUBFIELD_PATTERN.exec(rest)) {
17
- tokens.push({ type: "subfieldMarker", value: "*" });
18
- tokens.push({ type: "subfieldCode", value: match2[1] });
19
- tokens.push({ type: "value", value: match2[2] });
20
- lastIndex = SUBFIELD_PATTERN.lastIndex;
21
- }
22
- if (lastIndex < rest.length) {
23
- tokens.push({ type: "text", value: rest.slice(lastIndex) });
35
+ if (indicator !== void 0) {
36
+ tokens.push({ type: "indicator", value: indicator });
37
+ tokens.push({ type: "whitespace", value: gap2 });
24
38
  }
39
+ tokens.push(...tokenizeSubfields(rest));
25
40
  return tokens;
26
41
  }
27
42
  function tokenizeLineFormat(source) {
43
+ var _a;
28
44
  const tokens = [];
29
45
  const chunks = source.split(/(\n)/);
46
+ let continuesValue = false;
30
47
  for (const chunk of chunks) {
31
48
  if (chunk === "") continue;
32
49
  if (chunk === "\n") {
@@ -40,9 +57,12 @@ function tokenizeLineFormat(source) {
40
57
  if (leading) tokens.push({ type: "text", value: leading });
41
58
  tokens.push({ type: "terminator", value: "$" });
42
59
  if (trailing) tokens.push({ type: "text", value: trailing });
60
+ continuesValue = false;
43
61
  continue;
44
62
  }
45
- tokens.push(...tokenizeFieldLine(chunk));
63
+ const lineTokens = FIELD_LINE_PATTERN.test(chunk) ? tokenizeFieldLine(chunk) : tokenizeContinuationLine(chunk, continuesValue);
64
+ tokens.push(...lineTokens);
65
+ continuesValue = ((_a = lineTokens[lineTokens.length - 1]) == null ? void 0 : _a.type) === "value";
46
66
  }
47
67
  return tokens;
48
68
  }
@@ -9,6 +9,7 @@ var Popover = require('../../components/popover/Popover');
9
9
  var usePersistentState = require('../../hooks/usePersistentState');
10
10
  var tokenizeXml = require('./tokenizeXml');
11
11
  var styles = require('./XmlViewer.module.css');
12
+ var clipboard_utils = require('../../utils/clipboard.utils');
12
13
  var Button = require('../button/Button');
13
14
  var Icon = require('../icon/Icon');
14
15
 
@@ -54,9 +55,7 @@ function XmlViewer({
54
55
  validate: (stored) => typeof stored === "boolean"
55
56
  });
56
57
  const handleCopy = () => {
57
- var _a;
58
- (_a = navigator.clipboard) == null ? void 0 : _a.writeText(xml).catch(() => {
59
- });
58
+ void clipboard_utils.copyToClipboard(xml);
60
59
  };
61
60
  const handleDoubleClick = () => {
62
61
  const el = codeRef.current;
@@ -7,6 +7,7 @@ import { Popover } from '../../components/popover/Popover';
7
7
  import { usePersistentState } from '../../hooks/usePersistentState';
8
8
  import { tokenizeXml } from './tokenizeXml';
9
9
  import styles from './XmlViewer.module.css';
10
+ import { copyToClipboard } from '../../utils/clipboard.utils';
10
11
  import { Button } from '../button/Button';
11
12
  import { Icon } from '../icon/Icon';
12
13
 
@@ -48,9 +49,7 @@ function XmlViewer({
48
49
  validate: (stored) => typeof stored === "boolean"
49
50
  });
50
51
  const handleCopy = () => {
51
- var _a;
52
- (_a = navigator.clipboard) == null ? void 0 : _a.writeText(xml).catch(() => {
53
- });
52
+ void copyToClipboard(xml);
54
53
  };
55
54
  const handleDoubleClick = () => {
56
55
  const el = codeRef.current;
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "@dbcdk/react-components",
3
- "version": "0.0.194",
3
+ "version": "0.0.195",
4
4
  "description": "Reusable React components for DBC projects",
5
5
  "license": "ISC",
6
6
  "author": "",