@dbcdk/react-components 0.0.209 → 0.0.210

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 (36) hide show
  1. package/dist/client.cjs +10 -0
  2. package/dist/client.d.ts +4 -0
  3. package/dist/client.js +2 -0
  4. package/dist/components/forms/markdown-editor/MarkdownEditor.cjs +475 -0
  5. package/dist/components/forms/markdown-editor/MarkdownEditor.d.ts +68 -0
  6. package/dist/components/forms/markdown-editor/MarkdownEditor.js +468 -0
  7. package/dist/components/forms/markdown-editor/MarkdownEditor.module.css +202 -0
  8. package/dist/components/forms/markdown-editor/MarkdownViewer.cjs +29 -0
  9. package/dist/components/forms/markdown-editor/MarkdownViewer.d.ts +27 -0
  10. package/dist/components/forms/markdown-editor/MarkdownViewer.js +23 -0
  11. package/dist/components/forms/markdown-editor/MarkdownViewer.module.css +97 -0
  12. package/dist/components/forms/markdown-editor/markdown.utils.cjs +325 -0
  13. package/dist/components/forms/markdown-editor/markdown.utils.d.ts +66 -0
  14. package/dist/components/forms/markdown-editor/markdown.utils.js +310 -0
  15. package/dist/components/listbox/Listbox.cjs +2 -2
  16. package/dist/components/listbox/Listbox.d.ts +2 -2
  17. package/dist/components/listbox/Listbox.js +2 -2
  18. package/dist/components/meta-bar/MetaBar.cjs +2 -2
  19. package/dist/components/meta-bar/MetaBar.d.ts +2 -1
  20. package/dist/components/meta-bar/MetaBar.js +2 -2
  21. package/dist/components/meta-bar/MetaBar.module.css +7 -0
  22. package/dist/components/overlay/tooltip/TooltipProvider.cjs +10 -1
  23. package/dist/components/overlay/tooltip/TooltipProvider.js +11 -2
  24. package/dist/components/overlay/tooltip/useTooltipTrigger.cjs +9 -2
  25. package/dist/components/overlay/tooltip/useTooltipTrigger.js +9 -2
  26. package/dist/components/sidebar/components/sidebar-container/SidebarContainer.cjs +1 -1
  27. package/dist/components/sidebar/components/sidebar-container/SidebarContainer.js +1 -1
  28. package/dist/components/tabs/Tabs.cjs +83 -69
  29. package/dist/components/tabs/Tabs.d.ts +5 -1
  30. package/dist/components/tabs/Tabs.js +83 -69
  31. package/dist/components/tabs/Tabs.module.css +39 -0
  32. package/dist/index.cjs +213 -208
  33. package/dist/index.css +2 -0
  34. package/dist/index.d.ts +2 -0
  35. package/dist/index.js +1 -0
  36. package/package.json +4 -1
@@ -0,0 +1,310 @@
1
+ import { jsx, jsxs } from 'react/jsx-runtime';
2
+ import MarkdownIt from 'markdown-it';
3
+ import React from 'react';
4
+
5
+ const ESCAPE_PATTERN = /\\[!-/:-@[-`{-~]/;
6
+ const LINK_PATTERN = /\[((?:\\[^\n]|[^\]\\\n])+)\]\(((?:[^()\s]|\([^()\s]*\))+)\)/;
7
+ const escapeRegExp = (text) => text.replace(/[.*+?^$()|[\]\\{}]/g, "\\$&");
8
+ const linkPattern = (urlPlaceholder) => new RegExp(LINK_PATTERN.source.replace(/\)\\\)$/, `|${escapeRegExp(urlPlaceholder)})\\)`));
9
+ const LINK_PLACEHOLDER_TEXT = "linktekst";
10
+ const LINK_PLACEHOLDER_URL = "inds\xE6t url";
11
+ const parser = new MarkdownIt();
12
+ parser.validateLink = (url) => getSafeHref(url) !== void 0;
13
+ function getSafeHref(url) {
14
+ if ([...url].some((character) => character < " " || character === "\x7F")) return void 0;
15
+ const hasScheme = /^[a-z][a-z0-9+.-]*:/i.test(url);
16
+ return !hasScheme || /^(https?|mailto|tel):/i.test(url) ? url : void 0;
17
+ }
18
+ function findLinkAt(value, selectionStart, selectionEnd, urlPlaceholder = LINK_PLACEHOLDER_URL) {
19
+ const pattern = new RegExp(`${ESCAPE_PATTERN.source}|${linkPattern(urlPlaceholder).source}`, "g");
20
+ let match;
21
+ while ((match = pattern.exec(value)) !== null) {
22
+ if (match.index > selectionStart) return void 0;
23
+ const end = match.index + match[0].length;
24
+ if (match[1] !== void 0 && selectionEnd <= end) {
25
+ return { start: match.index, end, text: match[1] };
26
+ }
27
+ }
28
+ return void 0;
29
+ }
30
+ function escapeMarkdown(value) {
31
+ return value.replace(/[!-/:-@[-`{-~]/g, "\\$&");
32
+ }
33
+ function unescapeMarkdown(value) {
34
+ return value.replace(/\\([!-/:-@[-`{-~])/g, "$1");
35
+ }
36
+ const INLINE_SYNTAX = /\\(?=[!-/:-@[-`{-~]|$)|[`*_[<~|]|&(?=#?[a-z0-9]+;)/gi;
37
+ const BLOCK_SYNTAX = /^(\s*)(#{1,6}(?=\s|$)|>|[-+=](?=\s|$)|[-=]+\s*$)|^(\s*\d+)([.)])(?=\s|$)/;
38
+ const INDENT_ENTITIES = { " ": "&nbsp;", " ": "&#9;" };
39
+ const ENCODED_INDENT = /^(?:&nbsp;|&#9;)+/gm;
40
+ function escapePlainLine(line) {
41
+ if (!line.trim()) return line;
42
+ const indent = /^[ \t]*/.exec(line)[0];
43
+ const escaped = line.slice(indent.length).replace(INLINE_SYNTAX, "\\$&");
44
+ if (indent) return `${indent.replace(/[ \t]/g, (space) => INDENT_ENTITIES[space])}${escaped}`;
45
+ return escaped.replace(
46
+ BLOCK_SYNTAX,
47
+ (_, indent2, marker, number, delimiter) => marker === void 0 ? `${number}\\${delimiter}` : `${indent2}\\${marker}`
48
+ );
49
+ }
50
+ function plainTextToMarkdown(text) {
51
+ const lines = text.split("\n");
52
+ return lines.map((line, index) => {
53
+ const escaped = escapePlainLine(line);
54
+ return index < lines.length - 1 && line.trim() && lines[index + 1].trim() ? `${escaped}\\` : escaped;
55
+ }).join("\n");
56
+ }
57
+ function limitPlainText(previous, next, maxLength) {
58
+ if (maxLength === void 0 || next.length < previous.length || plainTextToMarkdown(next).length <= maxLength) {
59
+ return { text: next, caret: -1 };
60
+ }
61
+ let start = 0;
62
+ while (start < previous.length && start < next.length && previous[start] === next[start]) start++;
63
+ let end = 0;
64
+ while (end < previous.length - start && end < next.length - start && previous[previous.length - 1 - end] === next[next.length - 1 - end]) {
65
+ end++;
66
+ }
67
+ const inserted = next.slice(start, next.length - end);
68
+ const withInserted = (length) => `${next.slice(0, start)}${inserted.slice(0, length)}${next.slice(next.length - end)}`;
69
+ let low = 0;
70
+ let high = inserted.length;
71
+ while (low < high) {
72
+ const middle = Math.ceil((low + high) / 2);
73
+ if (plainTextToMarkdown(withInserted(middle)).length <= maxLength) low = middle;
74
+ else high = middle - 1;
75
+ }
76
+ const text = withInserted(low);
77
+ return text === previous ? void 0 : { text, caret: start + low };
78
+ }
79
+ function markdownToPlainText(markdown) {
80
+ return markdown.replace(ENCODED_INDENT, (indent) => indent.replace(/&nbsp;/g, " ").replace(/&#9;/g, " ")).replace(/\\([!-/:-@[-`{-~\n])/g, "$1");
81
+ }
82
+ function isPlainMarkdown(markdown) {
83
+ const normalize = (html) => html.replace(/<br>\n/g, "\n").replace(/(^|>|\n)[\u00a0\t]+/g, "$1");
84
+ return normalize(parser.render(markdown)) === normalize(parser.render(plainTextToMarkdown(markdownToPlainText(markdown))));
85
+ }
86
+ const SELECTION_SYNTAX = /\\[!-/:-@[-`{-~]|[`*_[<~|]|&(?=#?[a-z0-9]+;)/gi;
87
+ function escapeSyntax(text, startsLine) {
88
+ return text.split("\n").map((line, index) => {
89
+ const escaped = line.replace(
90
+ SELECTION_SYNTAX,
91
+ (part) => part.length === 2 ? part : `\\${part}`
92
+ );
93
+ if (index === 0 && !startsLine) return escaped;
94
+ return escaped.replace(
95
+ BLOCK_SYNTAX,
96
+ (_, indent, marker, number, delimiter) => marker === void 0 ? `${number}\\${delimiter}` : `${indent}\\${marker}`
97
+ );
98
+ }).join("\n");
99
+ }
100
+ function isSelectionEscaped(value, selectionStart, selectionEnd) {
101
+ const selectedText = value.slice(selectionStart, selectionEnd);
102
+ const startsLine = selectionStart === 0 || value[selectionStart - 1] === "\n";
103
+ return ESCAPE_PATTERN.test(selectedText) && escapeSyntax(selectedText, startsLine) === selectedText;
104
+ }
105
+ function isEscaped(value, index) {
106
+ let backslashes = 0;
107
+ while (index > 0 && value[--index] === "\\") backslashes++;
108
+ return backslashes % 2 === 1;
109
+ }
110
+ function formatMarkdownSelection(value, selectionStart, selectionEnd, format) {
111
+ var _a, _b;
112
+ if (format.type === "link") {
113
+ const textPlaceholder = (_a = format.textPlaceholder) != null ? _a : LINK_PLACEHOLDER_TEXT;
114
+ const urlPlaceholder = (_b = format.urlPlaceholder) != null ? _b : LINK_PLACEHOLDER_URL;
115
+ const link = findLinkAt(value, selectionStart, selectionEnd, urlPlaceholder);
116
+ if (link) {
117
+ return {
118
+ value: `${value.slice(0, link.start)}${link.text}${value.slice(link.end)}`,
119
+ selectionStart: link.start,
120
+ selectionEnd: link.start + link.text.length
121
+ };
122
+ }
123
+ const selectedText = value.slice(selectionStart, selectionEnd);
124
+ const textStart = selectionStart + 1;
125
+ if (/^(https?:\/\/|mailto:)\S+$/i.test(selectedText)) {
126
+ return {
127
+ value: `${value.slice(0, selectionStart)}[${textPlaceholder}](${selectedText})${value.slice(selectionEnd)}`,
128
+ selectionStart: textStart,
129
+ selectionEnd: textStart + textPlaceholder.length
130
+ };
131
+ }
132
+ const text = selectedText || textPlaceholder;
133
+ const urlStart = textStart + text.length + 2;
134
+ return {
135
+ value: `${value.slice(0, selectionStart)}[${text}](${urlPlaceholder})${value.slice(selectionEnd)}`,
136
+ selectionStart: selectedText ? urlStart : textStart,
137
+ selectionEnd: selectedText ? urlStart + urlPlaceholder.length : textStart + text.length
138
+ };
139
+ }
140
+ if (format.type === "escape") {
141
+ const selectedText = value.slice(selectionStart, selectionEnd);
142
+ const startsLine = selectionStart === 0 || value[selectionStart - 1] === "\n";
143
+ const replacement2 = isSelectionEscaped(value, selectionStart, selectionEnd) ? unescapeMarkdown(selectedText) : escapeSyntax(selectedText, startsLine);
144
+ return {
145
+ value: `${value.slice(0, selectionStart)}${replacement2}${value.slice(selectionEnd)}`,
146
+ selectionStart,
147
+ selectionEnd: selectionStart + replacement2.length
148
+ };
149
+ }
150
+ if (format.type === "wrap") {
151
+ const selectedText = value.slice(selectionStart, selectionEnd);
152
+ const markerStart = selectionStart - format.marker.length;
153
+ const isAlreadyWrapped = isMarkdownFormatActive(value, selectionStart, selectionEnd, format);
154
+ if (isAlreadyWrapped) {
155
+ return {
156
+ value: `${value.slice(0, markerStart)}${selectedText}${value.slice(selectionEnd + format.marker.length)}`,
157
+ selectionStart: markerStart,
158
+ selectionEnd: markerStart + selectedText.length
159
+ };
160
+ }
161
+ const replacement2 = `${format.marker}${selectedText}${format.marker}`;
162
+ const innerStart = selectionStart + format.marker.length;
163
+ return {
164
+ value: `${value.slice(0, selectionStart)}${replacement2}${value.slice(selectionEnd)}`,
165
+ selectionStart: innerStart,
166
+ selectionEnd: innerStart + selectedText.length
167
+ };
168
+ }
169
+ const previousNewline = selectionStart > 0 ? value.lastIndexOf("\n", selectionStart - 1) : -1;
170
+ const lineStart = previousNewline + 1;
171
+ const selectedEnd = selectionEnd > selectionStart && value[selectionEnd - 1] === "\n" ? selectionEnd - 1 : selectionEnd;
172
+ const lineEndIndex = value.indexOf("\n", selectedEnd);
173
+ const lineEnd = lineEndIndex === -1 ? value.length : lineEndIndex;
174
+ const selectedLines = value.slice(lineStart, lineEnd).split("\n");
175
+ const removePrefix = format.toggle && isMarkdownFormatActive(value, selectionStart, selectionEnd, format);
176
+ const formattedLines = selectedLines.map((line) => {
177
+ if (removePrefix) return line.slice(format.prefix.length);
178
+ if (format.prefix.startsWith("#")) return `${format.prefix}${line.replace(/^#{1,6}\s+/, "")}`;
179
+ return `${format.prefix}${line}`;
180
+ });
181
+ const replacement = formattedLines.join("\n");
182
+ return {
183
+ value: `${value.slice(0, lineStart)}${replacement}${value.slice(lineEnd)}`,
184
+ selectionStart: lineStart,
185
+ selectionEnd: lineStart + replacement.length
186
+ };
187
+ }
188
+ function isMarkdownFormatActive(value, selectionStart, selectionEnd, format) {
189
+ if (format.type === "link") {
190
+ return findLinkAt(value, selectionStart, selectionEnd, format.urlPlaceholder) !== void 0;
191
+ }
192
+ if (format.type === "escape") return isSelectionEscaped(value, selectionStart, selectionEnd);
193
+ if (format.type === "wrap") {
194
+ const character = format.marker[0];
195
+ let start = selectionStart;
196
+ let end = selectionEnd;
197
+ while (start > 0 && value[start - 1] === character && !isEscaped(value, start - 1)) start--;
198
+ while (end < value.length && value[end] === character && !isEscaped(value, end)) end++;
199
+ const markerCount = Math.min(selectionStart - start, end - selectionEnd);
200
+ return format.marker.length === 1 ? markerCount % 2 === 1 : markerCount >= 2;
201
+ }
202
+ const previousNewline = selectionStart > 0 ? value.lastIndexOf("\n", selectionStart - 1) : -1;
203
+ const lineStart = previousNewline + 1;
204
+ const selectedEnd = selectionEnd > selectionStart && value[selectionEnd - 1] === "\n" ? selectionEnd - 1 : selectionEnd;
205
+ const lineEndIndex = value.indexOf("\n", selectedEnd);
206
+ const lineEnd = lineEndIndex === -1 ? value.length : lineEndIndex;
207
+ const lines = value.slice(lineStart, lineEnd).split("\n");
208
+ if (format.prefix.startsWith("#")) {
209
+ return lines.every((line) => {
210
+ var _a;
211
+ return ((_a = /^(#{1,6}\s+)/.exec(line)) == null ? void 0 : _a[0]) === format.prefix;
212
+ });
213
+ }
214
+ return lines.every((line) => line.startsWith(format.prefix));
215
+ }
216
+ function getAttr(token, name) {
217
+ const value = token.attrGet(name);
218
+ return value === null ? void 0 : String(value);
219
+ }
220
+ function toStyle(style) {
221
+ var _a;
222
+ const align = style && ((_a = /^text-align:\s*(left|right|center)$/.exec(style)) == null ? void 0 : _a[1]);
223
+ return align ? { textAlign: align } : void 0;
224
+ }
225
+ function renderLeaf(token, key, options) {
226
+ var _a, _b;
227
+ switch (token.type) {
228
+ case "text":
229
+ return token.content;
230
+ case "softbreak":
231
+ return "\n";
232
+ case "hardbreak":
233
+ return /* @__PURE__ */ jsx("br", {}, key);
234
+ case "code_inline":
235
+ return /* @__PURE__ */ jsx("code", { children: token.content }, key);
236
+ case "code_block":
237
+ return /* @__PURE__ */ jsx("pre", { children: /* @__PURE__ */ jsx("code", { children: token.content }) }, key);
238
+ case "fence": {
239
+ const language = token.info.trim().split(/\s+/)[0];
240
+ return /* @__PURE__ */ jsx("pre", { children: /* @__PURE__ */ jsx("code", { className: language ? `language-${language}` : void 0, children: token.content }) }, key);
241
+ }
242
+ case "hr":
243
+ return /* @__PURE__ */ jsx("hr", {}, key);
244
+ case "image":
245
+ return parser.renderer.renderInlineAsText((_a = token.children) != null ? _a : [], parser.options, {});
246
+ case "inline":
247
+ return renderTokens((_b = token.children) != null ? _b : [], options);
248
+ default:
249
+ return token.content || null;
250
+ }
251
+ }
252
+ function renderElement(open, children, key, options) {
253
+ var _a;
254
+ if (open.hidden) return /* @__PURE__ */ jsx(React.Fragment, { children }, key);
255
+ if (/^h[1-6]$/.test(open.tag)) {
256
+ const level = Math.min(6, Math.max(1, Number(open.tag[1]) + ((_a = options.headingOffset) != null ? _a : 0)));
257
+ return React.createElement(`h${level}`, { key }, children);
258
+ }
259
+ if (open.tag === "a") {
260
+ const href = getAttr(open, "href");
261
+ const newTab = options.openLinksInNewTab && !/^(mailto|tel):/i.test(href != null ? href : "");
262
+ return /* @__PURE__ */ jsxs(
263
+ "a",
264
+ {
265
+ href,
266
+ title: getAttr(open, "title"),
267
+ target: newTab ? "_blank" : void 0,
268
+ rel: newTab ? "noopener noreferrer" : void 0,
269
+ children: [
270
+ children,
271
+ newTab && options.newTabHint
272
+ ]
273
+ },
274
+ key
275
+ );
276
+ }
277
+ if (open.tag === "ol") {
278
+ const start = getAttr(open, "start");
279
+ return /* @__PURE__ */ jsx("ol", { start: start ? Number(start) : void 0, children }, key);
280
+ }
281
+ if (open.tag === "th" || open.tag === "td") {
282
+ return React.createElement(open.tag, { key, style: toStyle(getAttr(open, "style")) }, children);
283
+ }
284
+ return React.createElement(open.tag, { key }, children);
285
+ }
286
+ function renderTokens(tokens, options) {
287
+ const root = [];
288
+ const stack = [];
289
+ tokens.forEach((token, index) => {
290
+ const siblings = stack.length ? stack[stack.length - 1].children : root;
291
+ if (token.nesting === 1) {
292
+ stack.push({ open: token, children: [] });
293
+ } else if (token.nesting === -1) {
294
+ const element = stack.pop();
295
+ if (!element) return;
296
+ const parent = stack.length ? stack[stack.length - 1].children : root;
297
+ parent.push(renderElement(element.open, element.children, index, options));
298
+ } else {
299
+ const leaf = renderLeaf(token, index, options);
300
+ if (Array.isArray(leaf)) siblings.push(/* @__PURE__ */ jsx(React.Fragment, { children: leaf }, index));
301
+ else if (leaf !== null) siblings.push(leaf);
302
+ }
303
+ });
304
+ return root;
305
+ }
306
+ function renderMarkdown(value, options = {}) {
307
+ return renderTokens(parser.parse(value, {}), options);
308
+ }
309
+
310
+ export { escapeMarkdown, formatMarkdownSelection, getSafeHref, isMarkdownFormatActive, isPlainMarkdown, limitPlainText, markdownToPlainText, plainTextToMarkdown, renderMarkdown };
@@ -111,9 +111,9 @@ function Listbox({
111
111
  ].filter(Boolean).join(" "),
112
112
  disabled: option.disabled,
113
113
  onFocus: () => setActiveValue(option.value),
114
- onClick: () => {
114
+ onClick: (event) => {
115
115
  setActiveValue(option.value);
116
- onOptionSelect(option.value);
116
+ onOptionSelect(option.value, event);
117
117
  },
118
118
  children: /* @__PURE__ */ jsxRuntime.jsxs("span", { className: styles__default.default.optionContent, children: [
119
119
  option.icon ? /* @__PURE__ */ jsxRuntime.jsx("span", { className: styles__default.default.icon, "aria-hidden": "true", children: option.icon }) : null,
@@ -1,4 +1,4 @@
1
- import { type HTMLAttributes, type ReactNode } from 'react';
1
+ import { type HTMLAttributes, type MouseEvent, type ReactNode } from 'react';
2
2
  export type ListboxOption<T extends string | number = string> = {
3
3
  value: T;
4
4
  label: ReactNode;
@@ -15,7 +15,7 @@ export type ListboxProps<T extends string | number = string> = Omit<HTMLAttribut
15
15
  selectedValues: readonly T[];
16
16
  selectionMode?: 'single' | 'multiple';
17
17
  autoFocusValue?: T;
18
- onOptionSelect: (value: T) => void;
18
+ onOptionSelect: (value: T, event: MouseEvent<HTMLButtonElement>) => void;
19
19
  onActiveChange?: (value: T) => void;
20
20
  renderAction?: (option: ListboxOption<T>, selected: boolean) => ReactNode;
21
21
  };
@@ -104,9 +104,9 @@ function Listbox({
104
104
  ].filter(Boolean).join(" "),
105
105
  disabled: option.disabled,
106
106
  onFocus: () => setActiveValue(option.value),
107
- onClick: () => {
107
+ onClick: (event) => {
108
108
  setActiveValue(option.value);
109
- onOptionSelect(option.value);
109
+ onOptionSelect(option.value, event);
110
110
  },
111
111
  children: /* @__PURE__ */ jsxs("span", { className: styles.optionContent, children: [
112
112
  option.icon ? /* @__PURE__ */ jsx("span", { className: styles.icon, "aria-hidden": "true", children: option.icon }) : null,
@@ -8,12 +8,12 @@ function _interopDefault (e) { return e && e.__esModule ? e : { default: e }; }
8
8
 
9
9
  var styles__default = /*#__PURE__*/_interopDefault(styles);
10
10
 
11
- function MetaBar({ items, separator = "\u2022" }) {
11
+ function MetaBar({ items, separator = "\u2022", size = "sm" }) {
12
12
  const visibleItems = items.filter(
13
13
  (item) => item.value !== null && item.value !== void 0 && item.value !== ""
14
14
  );
15
15
  if (visibleItems.length === 0) return null;
16
- return /* @__PURE__ */ jsxRuntime.jsx("div", { className: styles__default.default.meta, children: visibleItems.map((item, index) => /* @__PURE__ */ jsxRuntime.jsxs(react.Fragment, { children: [
16
+ return /* @__PURE__ */ jsxRuntime.jsx("div", { className: `${styles__default.default.meta} ${styles__default.default[size]}`, children: visibleItems.map((item, index) => /* @__PURE__ */ jsxRuntime.jsxs(react.Fragment, { children: [
17
17
  /* @__PURE__ */ jsxRuntime.jsxs("span", { className: item.muted === false ? styles__default.default.itemDefault : styles__default.default.itemMuted, children: [
18
18
  item.label && /* @__PURE__ */ jsxRuntime.jsxs("span", { children: [
19
19
  item.label,
@@ -6,7 +6,8 @@ export interface MetaItem {
6
6
  }
7
7
  interface MetaBarProps {
8
8
  items: MetaItem[];
9
+ size?: 'sm' | 'md';
9
10
  separator?: ReactNode;
10
11
  }
11
- export declare function MetaBar({ items, separator }: MetaBarProps): JSX.Element | null;
12
+ export declare function MetaBar({ items, separator, size }: MetaBarProps): JSX.Element | null;
12
13
  export {};
@@ -2,12 +2,12 @@ import { jsx, jsxs } from 'react/jsx-runtime';
2
2
  import { Fragment } from 'react';
3
3
  import styles from './MetaBar.module.css';
4
4
 
5
- function MetaBar({ items, separator = "\u2022" }) {
5
+ function MetaBar({ items, separator = "\u2022", size = "sm" }) {
6
6
  const visibleItems = items.filter(
7
7
  (item) => item.value !== null && item.value !== void 0 && item.value !== ""
8
8
  );
9
9
  if (visibleItems.length === 0) return null;
10
- return /* @__PURE__ */ jsx("div", { className: styles.meta, children: visibleItems.map((item, index) => /* @__PURE__ */ jsxs(Fragment, { children: [
10
+ return /* @__PURE__ */ jsx("div", { className: `${styles.meta} ${styles[size]}`, children: visibleItems.map((item, index) => /* @__PURE__ */ jsxs(Fragment, { children: [
11
11
  /* @__PURE__ */ jsxs("span", { className: item.muted === false ? styles.itemDefault : styles.itemMuted, children: [
12
12
  item.label && /* @__PURE__ */ jsxs("span", { children: [
13
13
  item.label,
@@ -3,9 +3,16 @@
3
3
  flex-wrap: wrap;
4
4
  align-items: center;
5
5
  gap: var(--spacing-xs);
6
+ }
7
+
8
+ .sm {
6
9
  font-size: var(--font-size-xs);
7
10
  }
8
11
 
12
+ .md {
13
+ font-size: var(--font-size-sm);
14
+ }
15
+
9
16
  .itemMuted,
10
17
  .itemDefault {
11
18
  display: inline-flex;
@@ -64,10 +64,18 @@ function shallowEqualActive(a, b) {
64
64
  function TooltipProvider({ children }) {
65
65
  const [active, setActive] = react.useState(null);
66
66
  const showTimerRef = react.useRef(null);
67
+ const pendingIdRef = react.useRef(null);
68
+ react.useEffect(() => {
69
+ return () => {
70
+ if (showTimerRef.current) clearTimeout(showTimerRef.current);
71
+ };
72
+ }, []);
67
73
  const show = react.useCallback((next) => {
68
74
  if (showTimerRef.current) clearTimeout(showTimerRef.current);
75
+ pendingIdRef.current = next.id;
69
76
  showTimerRef.current = setTimeout(() => {
70
77
  showTimerRef.current = null;
78
+ pendingIdRef.current = null;
71
79
  setActive((curr) => {
72
80
  const proposed = { ...next, open: true };
73
81
  return shallowEqualActive(curr, proposed) ? curr : proposed;
@@ -75,9 +83,10 @@ function TooltipProvider({ children }) {
75
83
  }, SHOW_DELAY_MS);
76
84
  }, []);
77
85
  const hide = react.useCallback((id) => {
78
- if (showTimerRef.current) {
86
+ if (showTimerRef.current && pendingIdRef.current === id) {
79
87
  clearTimeout(showTimerRef.current);
80
88
  showTimerRef.current = null;
89
+ pendingIdRef.current = null;
81
90
  }
82
91
  setActive((curr) => {
83
92
  if (!curr || curr.id !== id) return curr;
@@ -1,6 +1,6 @@
1
1
  'use client';
2
2
  import { jsxs, jsx } from 'react/jsx-runtime';
3
- import { createContext, useState, useRef, useCallback, useMemo, useContext, useEffect, useLayoutEffect } from 'react';
3
+ import { createContext, useState, useRef, useEffect, useCallback, useMemo, useContext, useLayoutEffect } from 'react';
4
4
  import { createPortal } from 'react-dom';
5
5
  import styles from './Tooltip.module.css';
6
6
 
@@ -58,10 +58,18 @@ function shallowEqualActive(a, b) {
58
58
  function TooltipProvider({ children }) {
59
59
  const [active, setActive] = useState(null);
60
60
  const showTimerRef = useRef(null);
61
+ const pendingIdRef = useRef(null);
62
+ useEffect(() => {
63
+ return () => {
64
+ if (showTimerRef.current) clearTimeout(showTimerRef.current);
65
+ };
66
+ }, []);
61
67
  const show = useCallback((next) => {
62
68
  if (showTimerRef.current) clearTimeout(showTimerRef.current);
69
+ pendingIdRef.current = next.id;
63
70
  showTimerRef.current = setTimeout(() => {
64
71
  showTimerRef.current = null;
72
+ pendingIdRef.current = null;
65
73
  setActive((curr) => {
66
74
  const proposed = { ...next, open: true };
67
75
  return shallowEqualActive(curr, proposed) ? curr : proposed;
@@ -69,9 +77,10 @@ function TooltipProvider({ children }) {
69
77
  }, SHOW_DELAY_MS);
70
78
  }, []);
71
79
  const hide = useCallback((id) => {
72
- if (showTimerRef.current) {
80
+ if (showTimerRef.current && pendingIdRef.current === id) {
73
81
  clearTimeout(showTimerRef.current);
74
82
  showTimerRef.current = null;
83
+ pendingIdRef.current = null;
75
84
  }
76
85
  setActive((curr) => {
77
86
  if (!curr || curr.id !== id) return curr;
@@ -26,12 +26,19 @@ function useTooltipTrigger(options) {
26
26
  const openTimer = react.useRef(null);
27
27
  const closeTimer = react.useRef(null);
28
28
  const openedByFocusRef = react.useRef(false);
29
- const clearTimers = () => {
29
+ const clearTimers = react.useCallback(() => {
30
30
  if (openTimer.current) window.clearTimeout(openTimer.current);
31
31
  if (closeTimer.current) window.clearTimeout(closeTimer.current);
32
32
  openTimer.current = null;
33
33
  closeTimer.current = null;
34
- };
34
+ }, []);
35
+ const hideTooltip = ctx.hide;
36
+ react.useEffect(() => {
37
+ return () => {
38
+ clearTimers();
39
+ hideTooltip(id);
40
+ };
41
+ }, [clearTimers, hideTooltip, id]);
35
42
  const lastSentRef = react.useRef(null);
36
43
  const show = react.useCallback(() => {
37
44
  if (!content) return;
@@ -24,12 +24,19 @@ function useTooltipTrigger(options) {
24
24
  const openTimer = useRef(null);
25
25
  const closeTimer = useRef(null);
26
26
  const openedByFocusRef = useRef(false);
27
- const clearTimers = () => {
27
+ const clearTimers = useCallback(() => {
28
28
  if (openTimer.current) window.clearTimeout(openTimer.current);
29
29
  if (closeTimer.current) window.clearTimeout(closeTimer.current);
30
30
  openTimer.current = null;
31
31
  closeTimer.current = null;
32
- };
32
+ }, []);
33
+ const hideTooltip = ctx.hide;
34
+ useEffect(() => {
35
+ return () => {
36
+ clearTimers();
37
+ hideTooltip(id);
38
+ };
39
+ }, [clearTimers, hideTooltip, id]);
33
40
  const lastSentRef = useRef(null);
34
41
  const show = useCallback(() => {
35
42
  if (!content) return;
@@ -186,7 +186,7 @@ function SidebarContainer({
186
186
  ] }) }),
187
187
  /* @__PURE__ */ jsxRuntime.jsxs("div", { className: styles__default.default.content, children: [
188
188
  !hideSearch && /* @__PURE__ */ jsxRuntime.jsx("div", { className: styles__default.default.filter, children: /* @__PURE__ */ jsxRuntime.jsx(SidenavFiltering__default.default, { placeholder: searchPlaceholder, showSettings }) }),
189
- /* @__PURE__ */ jsxRuntime.jsx("div", { className: `${styles__default.default.links} hideScrollBar`, children: /* @__PURE__ */ jsxRuntime.jsx(SidebarItems.SidebarItems, { activeLink }) })
189
+ /* @__PURE__ */ jsxRuntime.jsx("div", { className: styles__default.default.links, children: /* @__PURE__ */ jsxRuntime.jsx(SidebarItems.SidebarItems, { activeLink }) })
190
190
  ] }),
191
191
  footer && /* @__PURE__ */ jsxRuntime.jsx("div", { className: styles__default.default.footerSlot, children: footer }),
192
192
  /* @__PURE__ */ jsxRuntime.jsxs("div", { className: styles__default.default.footer, children: [
@@ -179,7 +179,7 @@ function SidebarContainer({
179
179
  ] }) }),
180
180
  /* @__PURE__ */ jsxs("div", { className: styles.content, children: [
181
181
  !hideSearch && /* @__PURE__ */ jsx("div", { className: styles.filter, children: /* @__PURE__ */ jsx(SidenavFiltering, { placeholder: searchPlaceholder, showSettings }) }),
182
- /* @__PURE__ */ jsx("div", { className: `${styles.links} hideScrollBar`, children: /* @__PURE__ */ jsx(SidebarItems, { activeLink }) })
182
+ /* @__PURE__ */ jsx("div", { className: styles.links, children: /* @__PURE__ */ jsx(SidebarItems, { activeLink }) })
183
183
  ] }),
184
184
  footer && /* @__PURE__ */ jsx("div", { className: styles.footerSlot, children: footer }),
185
185
  /* @__PURE__ */ jsxs("div", { className: styles.footer, children: [