@mirror-physics/fractal-ui 0.2.0-next.9 → 0.2.0-next.90
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.
- package/README.md +85 -0
- package/dist/assets/typography/MirrorSans-OFL.txt +93 -0
- package/dist/assets/typography/MirrorSans-README.md +9 -0
- package/dist/assets/typography/MirrorSans-Variable.ttf +0 -0
- package/dist/assets/typography/MirrorSans-Variable.woff2 +0 -0
- package/dist/chunk-46TOMY4G.js +340 -0
- package/dist/chunk-46TOMY4G.js.map +1 -0
- package/dist/column-editor.cjs +378 -0
- package/dist/column-editor.cjs.map +1 -0
- package/dist/column-editor.css +36 -0
- package/dist/column-editor.css.map +1 -0
- package/dist/column-editor.d.cts +20 -0
- package/dist/column-editor.d.ts +20 -0
- package/dist/column-editor.js +7 -0
- package/dist/column-editor.js.map +1 -0
- package/dist/index.cjs +2681 -404
- package/dist/index.cjs.map +1 -1
- package/dist/index.css +2582 -193
- package/dist/index.css.map +1 -1
- package/dist/index.d.cts +468 -22
- package/dist/index.d.ts +468 -22
- package/dist/index.js +2445 -536
- package/dist/index.js.map +1 -1
- package/dist/lattice-FAYE5KWW.svg +3 -0
- package/dist/tokens.css +123 -17
- package/package.json +22 -5
package/dist/index.js
CHANGED
|
@@ -1,208 +1,418 @@
|
|
|
1
|
-
|
|
2
|
-
|
|
3
|
-
|
|
4
|
-
|
|
5
|
-
|
|
6
|
-
function cn(...inputs) {
|
|
7
|
-
return clsx(inputs);
|
|
8
|
-
}
|
|
1
|
+
import {
|
|
2
|
+
Button,
|
|
3
|
+
ColumnEditor,
|
|
4
|
+
cn
|
|
5
|
+
} from "./chunk-46TOMY4G.js";
|
|
9
6
|
|
|
10
|
-
// src/components/
|
|
11
|
-
import {
|
|
12
|
-
|
|
13
|
-
|
|
14
|
-
|
|
15
|
-
|
|
16
|
-
|
|
17
|
-
|
|
18
|
-
|
|
19
|
-
|
|
20
|
-
|
|
7
|
+
// src/components/CodeBlock/CodeBlock.tsx
|
|
8
|
+
import { useEffect, useMemo, useRef, useState } from "react";
|
|
9
|
+
import CodeMirror from "@uiw/react-codemirror";
|
|
10
|
+
import { HighlightStyle, foldGutter, foldService, syntaxHighlighting } from "@codemirror/language";
|
|
11
|
+
import { json } from "@codemirror/lang-json";
|
|
12
|
+
import {
|
|
13
|
+
Decoration,
|
|
14
|
+
EditorView,
|
|
15
|
+
MatchDecorator,
|
|
16
|
+
ViewPlugin,
|
|
17
|
+
lineNumbers as lineNumberGutter
|
|
18
|
+
} from "@codemirror/view";
|
|
19
|
+
import { tags } from "@lezer/highlight";
|
|
20
|
+
import { Check, Copy } from "@mirror-physics/fractal-icons";
|
|
21
|
+
import { jsx, jsxs } from "react/jsx-runtime";
|
|
22
|
+
var codeTheme = EditorView.theme({
|
|
23
|
+
"&": {
|
|
24
|
+
backgroundColor: "transparent",
|
|
25
|
+
color: "var(--fg-primary)",
|
|
26
|
+
fontSize: "0.75rem"
|
|
21
27
|
},
|
|
22
|
-
|
|
23
|
-
|
|
24
|
-
|
|
25
|
-
|
|
26
|
-
|
|
27
|
-
500: "var(--pink-500)",
|
|
28
|
-
600: "var(--pink-600)",
|
|
29
|
-
700: "var(--pink-700)"
|
|
28
|
+
"&.cm-focused": { outline: "none" },
|
|
29
|
+
".cm-scroller": {
|
|
30
|
+
fontFamily: "var(--font-mono)",
|
|
31
|
+
lineHeight: "1.55",
|
|
32
|
+
overscrollBehavior: "none"
|
|
30
33
|
},
|
|
31
|
-
|
|
32
|
-
|
|
33
|
-
|
|
34
|
-
|
|
35
|
-
200: "var(--orange-200)",
|
|
36
|
-
500: "var(--orange-500)",
|
|
37
|
-
600: "var(--orange-600)",
|
|
38
|
-
700: "var(--orange-700)"
|
|
34
|
+
".cm-content": { padding: "10px 0" },
|
|
35
|
+
".cm-line": {
|
|
36
|
+
padding: "0 12px 0 calc(12px + var(--fractal-code-wrap-indent, 0ch))",
|
|
37
|
+
textIndent: "calc(0px - var(--fractal-code-wrap-indent, 0ch))"
|
|
39
38
|
},
|
|
40
|
-
|
|
41
|
-
|
|
42
|
-
|
|
43
|
-
|
|
44
|
-
|
|
45
|
-
|
|
46
|
-
|
|
47
|
-
|
|
48
|
-
|
|
49
|
-
|
|
50
|
-
|
|
51
|
-
|
|
52
|
-
|
|
53
|
-
|
|
54
|
-
|
|
55
|
-
|
|
56
|
-
|
|
57
|
-
|
|
58
|
-
|
|
59
|
-
|
|
60
|
-
|
|
61
|
-
|
|
62
|
-
|
|
63
|
-
|
|
64
|
-
|
|
65
|
-
|
|
66
|
-
transition: "
|
|
67
|
-
}
|
|
68
|
-
|
|
69
|
-
|
|
70
|
-
|
|
39
|
+
".cm-cursor, .cm-dropCursor": { borderLeftColor: "var(--fg-primary)" },
|
|
40
|
+
".cm-gutters": {
|
|
41
|
+
backgroundColor: "var(--bg-canvas)",
|
|
42
|
+
borderRight: "1px solid var(--border-subtle)",
|
|
43
|
+
color: "var(--fg-tertiary)"
|
|
44
|
+
},
|
|
45
|
+
".cm-lineNumbers .cm-gutterElement": { padding: "0 10px 0 4px" },
|
|
46
|
+
".cm-foldGutter": { width: "14px" },
|
|
47
|
+
".cm-foldGutter .cm-gutterElement": {
|
|
48
|
+
position: "relative",
|
|
49
|
+
display: "block",
|
|
50
|
+
width: "14px",
|
|
51
|
+
padding: "0"
|
|
52
|
+
},
|
|
53
|
+
".cm-foldGutter .cm-gutterElement > span": {
|
|
54
|
+
position: "absolute",
|
|
55
|
+
top: "2px",
|
|
56
|
+
left: "0",
|
|
57
|
+
display: "inline-flex",
|
|
58
|
+
width: "14px",
|
|
59
|
+
height: "14px",
|
|
60
|
+
alignItems: "center",
|
|
61
|
+
justifyContent: "center",
|
|
62
|
+
padding: "0",
|
|
63
|
+
color: "var(--fg-tertiary)",
|
|
64
|
+
lineHeight: "14px",
|
|
65
|
+
transition: "color 120ms ease"
|
|
66
|
+
},
|
|
67
|
+
'.cm-foldGutter .cm-gutterElement > span[title="Fold line"]': { transform: "translateY(-3px)" },
|
|
68
|
+
".cm-foldGutter .cm-gutterElement > span:hover": { color: "var(--fg-secondary)" },
|
|
69
|
+
".fractal-code-block__escape": { color: "var(--fg-secondary)" },
|
|
70
|
+
".cm-activeLine, .cm-activeLineGutter": { backgroundColor: "var(--bg-surface-1)" },
|
|
71
|
+
".cm-selectionBackground, &.cm-focused .cm-selectionBackground, ::selection": {
|
|
72
|
+
backgroundColor: "var(--accent-surface-stroke) !important"
|
|
73
|
+
},
|
|
74
|
+
".cm-searchMatch": {
|
|
75
|
+
backgroundColor: "var(--warning-surface)",
|
|
76
|
+
outline: "1px solid var(--warning-surface-stroke)"
|
|
77
|
+
},
|
|
78
|
+
".cm-searchMatch.cm-searchMatch-selected": { backgroundColor: "var(--warning-subtle)" },
|
|
79
|
+
".cm-panels": { backgroundColor: "var(--bg-surface-1)", color: "var(--fg-primary)" },
|
|
80
|
+
".cm-tooltip": {
|
|
81
|
+
borderColor: "var(--border-subtle)",
|
|
82
|
+
backgroundColor: "var(--bg-canvas)",
|
|
83
|
+
color: "var(--fg-primary)"
|
|
71
84
|
}
|
|
72
|
-
|
|
73
|
-
|
|
74
|
-
|
|
85
|
+
});
|
|
86
|
+
var fractalHighlightStyle = HighlightStyle.define([
|
|
87
|
+
{ tag: tags.comment, color: "var(--fg-tertiary)", fontStyle: "italic" },
|
|
88
|
+
{ tag: [tags.keyword, tags.controlKeyword, tags.operatorKeyword], color: "var(--purple-default)" },
|
|
89
|
+
{ tag: [tags.string, tags.special(tags.string)], color: "var(--purple-default)" },
|
|
90
|
+
{ tag: [tags.number, tags.bool, tags.null], color: "var(--orange-default)" },
|
|
91
|
+
{ tag: [tags.function(tags.variableName), tags.labelName], color: "var(--accent-default)" },
|
|
92
|
+
{ tag: [tags.typeName, tags.className, tags.namespace], color: "var(--pink-default)" },
|
|
93
|
+
{ tag: [tags.propertyName, tags.attributeName], color: "var(--success-default)" },
|
|
94
|
+
{ tag: [tags.operator, tags.punctuation], color: "var(--fg-secondary)" },
|
|
95
|
+
{ tag: tags.bracket, color: "var(--accent-default)" },
|
|
96
|
+
{ tag: [tags.heading, tags.strong], color: "var(--fg-primary)", fontWeight: "600" },
|
|
97
|
+
{ tag: tags.emphasis, fontStyle: "italic" },
|
|
98
|
+
{ tag: tags.link, color: "var(--accent-default)", textDecoration: "underline" },
|
|
99
|
+
{ tag: tags.invalid, color: "var(--error-default)", textDecoration: "underline wavy" }
|
|
100
|
+
]);
|
|
101
|
+
var jsonSupport = json();
|
|
102
|
+
var JSON_LANGUAGE_NAMES = /* @__PURE__ */ new Set(["json", "jsonl", "ndjson", "geojson"]);
|
|
103
|
+
var JSON_LINES_LANGUAGE_NAMES = /* @__PURE__ */ new Set(["jsonl", "ndjson"]);
|
|
104
|
+
var JSON_LINES_PRETTY_PRINT_THRESHOLD = 160;
|
|
105
|
+
var JSON_PROPERTY_PREFIX = /^(\s*"(?:\\.|[^"\\])*"\s*:\s*)/;
|
|
106
|
+
function countVisualColumns(value) {
|
|
107
|
+
let columns = 0;
|
|
108
|
+
for (const character of value) columns += character === " " ? 2 : 1;
|
|
109
|
+
return columns;
|
|
110
|
+
}
|
|
111
|
+
function getWrappedLineIndent(line) {
|
|
112
|
+
const leadingWhitespace = line.match(/^\s*/)?.[0] ?? "";
|
|
113
|
+
if (JSON_PROPERTY_PREFIX.test(line)) return Math.min(countVisualColumns(leadingWhitespace), 24);
|
|
114
|
+
return Math.min(countVisualColumns(leadingWhitespace) + 2, 12);
|
|
115
|
+
}
|
|
116
|
+
function buildWrappedLineIndentation(view) {
|
|
117
|
+
const decorations = [];
|
|
118
|
+
const decoratedLines = /* @__PURE__ */ new Set();
|
|
119
|
+
for (const visibleRange of view.visibleRanges) {
|
|
120
|
+
let position = visibleRange.from;
|
|
121
|
+
while (position <= visibleRange.to) {
|
|
122
|
+
const line = view.state.doc.lineAt(position);
|
|
123
|
+
if (!decoratedLines.has(line.from)) {
|
|
124
|
+
const indent = getWrappedLineIndent(line.text);
|
|
125
|
+
decorations.push(Decoration.line({
|
|
126
|
+
attributes: { style: `--fractal-code-wrap-indent: ${indent}ch` }
|
|
127
|
+
}).range(line.from));
|
|
128
|
+
decoratedLines.add(line.from);
|
|
129
|
+
}
|
|
130
|
+
if (line.to >= visibleRange.to) break;
|
|
131
|
+
position = line.to + 1;
|
|
75
132
|
}
|
|
76
|
-
return { ...base, backgroundColor: "transparent", border: "1px solid var(--fg-disabled)", color: "var(--fg-disabled)" };
|
|
77
133
|
}
|
|
78
|
-
|
|
79
|
-
|
|
80
|
-
|
|
81
|
-
|
|
82
|
-
|
|
83
|
-
|
|
84
|
-
|
|
85
|
-
|
|
86
|
-
|
|
87
|
-
|
|
88
|
-
|
|
89
|
-
|
|
90
|
-
|
|
91
|
-
|
|
92
|
-
|
|
93
|
-
|
|
94
|
-
|
|
95
|
-
|
|
96
|
-
|
|
97
|
-
case "secondary":
|
|
98
|
-
return {
|
|
99
|
-
...base,
|
|
100
|
-
backgroundColor: isActive ? "var(--bg-surface-2)" : isHovered ? "var(--bg-surface-1)" : "var(--bg-canvas)",
|
|
101
|
-
border: "1px solid var(--border-subtle)",
|
|
102
|
-
color: "var(--fg-primary)"
|
|
103
|
-
};
|
|
104
|
-
// Ghost: no border. Rest=transparent, hover/press=surface-1.
|
|
105
|
-
case "ghost":
|
|
106
|
-
return {
|
|
107
|
-
...base,
|
|
108
|
-
backgroundColor: isHovered || isActive ? "var(--bg-surface-1)" : "transparent",
|
|
109
|
-
border: "none",
|
|
110
|
-
color: "var(--fg-primary)"
|
|
111
|
-
};
|
|
112
|
-
// Danger: low-intensity destructive action. Text stays steady; hover deepens the light red surface.
|
|
113
|
-
case "danger":
|
|
114
|
-
return {
|
|
115
|
-
...base,
|
|
116
|
-
backgroundColor: isHovered || isActive ? "var(--danger-button-surface-hover)" : "var(--danger-button-surface)",
|
|
117
|
-
border: "none",
|
|
118
|
-
color: "var(--danger-button-fg)"
|
|
119
|
-
};
|
|
120
|
-
default:
|
|
121
|
-
return base;
|
|
134
|
+
return Decoration.set(decorations, true);
|
|
135
|
+
}
|
|
136
|
+
var wrappedLineIndentation = ViewPlugin.fromClass(class {
|
|
137
|
+
constructor(view) {
|
|
138
|
+
this.decorations = buildWrappedLineIndentation(view);
|
|
139
|
+
}
|
|
140
|
+
update(update) {
|
|
141
|
+
this.decorations = buildWrappedLineIndentation(update.view);
|
|
142
|
+
}
|
|
143
|
+
}, {
|
|
144
|
+
decorations: (plugin) => plugin.decorations
|
|
145
|
+
});
|
|
146
|
+
var jsonEscapeMatcher = new MatchDecorator({
|
|
147
|
+
regexp: /\\(?:["\\/bfnrt]|u[0-9a-fA-F]{4})/g,
|
|
148
|
+
decoration: Decoration.mark({ class: "fractal-code-block__escape" })
|
|
149
|
+
});
|
|
150
|
+
var jsonEscapeHighlighting = ViewPlugin.fromClass(class {
|
|
151
|
+
constructor(view) {
|
|
152
|
+
this.decorations = jsonEscapeMatcher.createDeco(view);
|
|
122
153
|
}
|
|
154
|
+
update(update) {
|
|
155
|
+
this.decorations = jsonEscapeMatcher.updateDeco(update, this.decorations);
|
|
156
|
+
}
|
|
157
|
+
}, {
|
|
158
|
+
decorations: (plugin) => plugin.decorations
|
|
159
|
+
});
|
|
160
|
+
function formatJsonLinesForDisplay(value) {
|
|
161
|
+
return value.split(/\r?\n/).map((line) => {
|
|
162
|
+
const firstContentIndex = line.search(/\S/);
|
|
163
|
+
if (firstContentIndex < 0 || line.length - firstContentIndex <= JSON_LINES_PRETTY_PRINT_THRESHOLD) return line;
|
|
164
|
+
const indentation = line.slice(0, firstContentIndex);
|
|
165
|
+
try {
|
|
166
|
+
const parsed = JSON.parse(line.slice(firstContentIndex));
|
|
167
|
+
if (parsed === null || typeof parsed !== "object") return line;
|
|
168
|
+
return JSON.stringify(parsed, null, 2).split("\n").map((formattedLine) => `${indentation}${formattedLine}`).join("\n");
|
|
169
|
+
} catch {
|
|
170
|
+
return line;
|
|
171
|
+
}
|
|
172
|
+
}).join("\n");
|
|
123
173
|
}
|
|
124
|
-
|
|
125
|
-
|
|
126
|
-
|
|
127
|
-
|
|
128
|
-
|
|
129
|
-
|
|
130
|
-
|
|
131
|
-
|
|
132
|
-
|
|
133
|
-
{
|
|
134
|
-
|
|
135
|
-
|
|
136
|
-
|
|
137
|
-
|
|
138
|
-
|
|
139
|
-
onMouseEnter: (e) => {
|
|
140
|
-
setIsHovered(true);
|
|
141
|
-
props.onMouseEnter?.(e);
|
|
142
|
-
},
|
|
143
|
-
onMouseLeave: (e) => {
|
|
144
|
-
setIsHovered(false);
|
|
145
|
-
setIsActive(false);
|
|
146
|
-
props.onMouseLeave?.(e);
|
|
147
|
-
},
|
|
148
|
-
onMouseDown: (e) => {
|
|
149
|
-
setIsActive(true);
|
|
150
|
-
props.onMouseDown?.(e);
|
|
151
|
-
},
|
|
152
|
-
onMouseUp: (e) => {
|
|
153
|
-
setIsActive(false);
|
|
154
|
-
props.onMouseUp?.(e);
|
|
155
|
-
},
|
|
156
|
-
...props,
|
|
157
|
-
children: [
|
|
158
|
-
iconPosition !== "right" && icon,
|
|
159
|
-
!hasIconOnly && children,
|
|
160
|
-
iconPosition === "right" && icon
|
|
161
|
-
]
|
|
174
|
+
function findJsonContainerEnd(document2, start) {
|
|
175
|
+
const openingCharacter = document2[start];
|
|
176
|
+
if (openingCharacter !== "{" && openingCharacter !== "[") return null;
|
|
177
|
+
const closingCharacters = [];
|
|
178
|
+
let isInsideString = false;
|
|
179
|
+
let isEscaped = false;
|
|
180
|
+
for (let index = start; index < document2.length; index += 1) {
|
|
181
|
+
const character = document2[index];
|
|
182
|
+
if (isInsideString) {
|
|
183
|
+
if (isEscaped) {
|
|
184
|
+
isEscaped = false;
|
|
185
|
+
} else if (character === "\\") {
|
|
186
|
+
isEscaped = true;
|
|
187
|
+
} else if (character === '"') {
|
|
188
|
+
isInsideString = false;
|
|
162
189
|
}
|
|
190
|
+
continue;
|
|
191
|
+
}
|
|
192
|
+
if (character === '"') {
|
|
193
|
+
isInsideString = true;
|
|
194
|
+
} else if (character === "{") {
|
|
195
|
+
closingCharacters.push("}");
|
|
196
|
+
} else if (character === "[") {
|
|
197
|
+
closingCharacters.push("]");
|
|
198
|
+
} else if (character === "}" || character === "]") {
|
|
199
|
+
if (closingCharacters.pop() !== character) return null;
|
|
200
|
+
if (closingCharacters.length === 0) return index;
|
|
201
|
+
}
|
|
202
|
+
}
|
|
203
|
+
return null;
|
|
204
|
+
}
|
|
205
|
+
var jsonLinesFoldSupport = foldService.of((state, lineStart, lineEnd) => {
|
|
206
|
+
const line = state.doc.sliceString(lineStart, lineEnd);
|
|
207
|
+
const firstContentIndex = line.search(/\S/);
|
|
208
|
+
if (firstContentIndex < 0) return null;
|
|
209
|
+
const containerStart = lineStart + firstContentIndex;
|
|
210
|
+
const openingCharacter = line[firstContentIndex];
|
|
211
|
+
if (openingCharacter !== "{" && openingCharacter !== "[") return null;
|
|
212
|
+
const document2 = state.doc.toString();
|
|
213
|
+
const containerEnd = findJsonContainerEnd(document2, containerStart);
|
|
214
|
+
if (containerEnd === null || containerEnd - containerStart < 2) return null;
|
|
215
|
+
try {
|
|
216
|
+
const parsed = JSON.parse(document2.slice(containerStart, containerEnd + 1));
|
|
217
|
+
if (parsed === null || typeof parsed !== "object") return null;
|
|
218
|
+
} catch {
|
|
219
|
+
return null;
|
|
220
|
+
}
|
|
221
|
+
return {
|
|
222
|
+
from: containerStart + 1,
|
|
223
|
+
to: containerEnd
|
|
224
|
+
};
|
|
225
|
+
});
|
|
226
|
+
function resolveLanguage(language, fileName) {
|
|
227
|
+
const normalized = language?.trim().toLowerCase();
|
|
228
|
+
const extension = fileName?.split(/[?#]/, 1)[0].split(".").pop()?.toLowerCase();
|
|
229
|
+
if (normalized && JSON_LANGUAGE_NAMES.has(normalized) || extension && JSON_LANGUAGE_NAMES.has(extension)) {
|
|
230
|
+
const isJsonLines = Boolean(
|
|
231
|
+
normalized && JSON_LINES_LANGUAGE_NAMES.has(normalized) || extension && JSON_LINES_LANGUAGE_NAMES.has(extension)
|
|
163
232
|
);
|
|
233
|
+
return { label: isJsonLines ? "JSONL" : "JSON", support: jsonSupport, isJsonLines };
|
|
164
234
|
}
|
|
165
|
-
)
|
|
166
|
-
|
|
235
|
+
if (normalized && !["text", "txt", "plaintext", "plain"].includes(normalized)) {
|
|
236
|
+
return { label: language?.trim(), support: null, isJsonLines: false };
|
|
237
|
+
}
|
|
238
|
+
return { support: null, isJsonLines: false };
|
|
239
|
+
}
|
|
240
|
+
function CodeBlock({
|
|
241
|
+
value,
|
|
242
|
+
language,
|
|
243
|
+
fileName,
|
|
244
|
+
label,
|
|
245
|
+
editable = false,
|
|
246
|
+
onChange,
|
|
247
|
+
lineNumbers = true,
|
|
248
|
+
wrap = true,
|
|
249
|
+
copyable = true,
|
|
250
|
+
ariaLabel,
|
|
251
|
+
height,
|
|
252
|
+
minHeight,
|
|
253
|
+
maxHeight = "28rem",
|
|
254
|
+
placeholder,
|
|
255
|
+
autoFocus,
|
|
256
|
+
className,
|
|
257
|
+
...props
|
|
258
|
+
}) {
|
|
259
|
+
const resolvedLanguage = useMemo(() => resolveLanguage(language, fileName), [fileName, language]);
|
|
260
|
+
const displayValue = useMemo(
|
|
261
|
+
() => !editable && resolvedLanguage.isJsonLines ? formatJsonLinesForDisplay(value) : value,
|
|
262
|
+
[editable, resolvedLanguage.isJsonLines, value]
|
|
263
|
+
);
|
|
264
|
+
const [copyStatus, setCopyStatus] = useState("idle");
|
|
265
|
+
const copyResetTimer = useRef(null);
|
|
266
|
+
useEffect(() => () => {
|
|
267
|
+
if (copyResetTimer.current) clearTimeout(copyResetTimer.current);
|
|
268
|
+
}, []);
|
|
269
|
+
const extensions = useMemo(() => [
|
|
270
|
+
codeTheme,
|
|
271
|
+
syntaxHighlighting(fractalHighlightStyle),
|
|
272
|
+
...resolvedLanguage.support ? [resolvedLanguage.support] : [],
|
|
273
|
+
...resolvedLanguage.support ? [jsonEscapeHighlighting] : [],
|
|
274
|
+
...resolvedLanguage.isJsonLines ? [jsonLinesFoldSupport] : [],
|
|
275
|
+
...lineNumbers ? [foldGutter(), lineNumberGutter()] : [],
|
|
276
|
+
...wrap ? [EditorView.lineWrapping, wrappedLineIndentation] : []
|
|
277
|
+
], [lineNumbers, resolvedLanguage.isJsonLines, resolvedLanguage.support, wrap]);
|
|
278
|
+
const languageLabel = resolvedLanguage.label;
|
|
279
|
+
const toolbarLabel = label ?? fileName ?? languageLabel;
|
|
280
|
+
const surfaceLabel = ariaLabel ?? (fileName ? `${fileName} ${editable ? "editor" : "viewer"}` : `Code ${editable ? "editor" : "viewer"}`);
|
|
281
|
+
const copyCode = async () => {
|
|
282
|
+
try {
|
|
283
|
+
await navigator.clipboard.writeText(value);
|
|
284
|
+
setCopyStatus("copied");
|
|
285
|
+
} catch {
|
|
286
|
+
setCopyStatus("error");
|
|
287
|
+
}
|
|
288
|
+
if (copyResetTimer.current) clearTimeout(copyResetTimer.current);
|
|
289
|
+
copyResetTimer.current = setTimeout(() => setCopyStatus("idle"), 1800);
|
|
290
|
+
};
|
|
291
|
+
const showToolbar = toolbarLabel !== void 0 || copyable || editable;
|
|
292
|
+
return /* @__PURE__ */ jsxs(
|
|
293
|
+
"div",
|
|
294
|
+
{
|
|
295
|
+
className: cn(
|
|
296
|
+
"fractal-code-block",
|
|
297
|
+
editable && "fractal-code-block--editable",
|
|
298
|
+
!lineNumbers && "fractal-code-block--no-line-numbers",
|
|
299
|
+
className
|
|
300
|
+
),
|
|
301
|
+
...props,
|
|
302
|
+
children: [
|
|
303
|
+
showToolbar && /* @__PURE__ */ jsxs("div", { className: "fractal-code-block__toolbar", children: [
|
|
304
|
+
/* @__PURE__ */ jsxs("div", { className: "fractal-code-block__identity", children: [
|
|
305
|
+
toolbarLabel !== void 0 && /* @__PURE__ */ jsx("span", { className: "fractal-code-block__label", title: typeof toolbarLabel === "string" ? toolbarLabel : void 0, children: toolbarLabel }),
|
|
306
|
+
fileName && languageLabel && /* @__PURE__ */ jsx("span", { className: "fractal-code-block__language", children: languageLabel }),
|
|
307
|
+
editable && /* @__PURE__ */ jsx("span", { className: "fractal-code-block__mode", children: "Editing" })
|
|
308
|
+
] }),
|
|
309
|
+
copyable && /* @__PURE__ */ jsxs(
|
|
310
|
+
"button",
|
|
311
|
+
{
|
|
312
|
+
type: "button",
|
|
313
|
+
className: "fractal-code-block__copy",
|
|
314
|
+
"aria-label": copyStatus === "copied" ? "Code copied" : "Copy code",
|
|
315
|
+
onClick: () => void copyCode(),
|
|
316
|
+
children: [
|
|
317
|
+
copyStatus === "copied" ? /* @__PURE__ */ jsx(Check, { size: 14 }) : /* @__PURE__ */ jsx(Copy, { size: 14 }),
|
|
318
|
+
/* @__PURE__ */ jsx("span", { children: copyStatus === "copied" ? "Copied" : copyStatus === "error" ? "Copy failed" : "Copy" })
|
|
319
|
+
]
|
|
320
|
+
}
|
|
321
|
+
)
|
|
322
|
+
] }),
|
|
323
|
+
/* @__PURE__ */ jsx("div", { className: "fractal-code-block__surface", children: /* @__PURE__ */ jsx(
|
|
324
|
+
CodeMirror,
|
|
325
|
+
{
|
|
326
|
+
"aria-label": surfaceLabel,
|
|
327
|
+
value: displayValue,
|
|
328
|
+
editable,
|
|
329
|
+
readOnly: !editable,
|
|
330
|
+
onChange,
|
|
331
|
+
extensions,
|
|
332
|
+
theme: "none",
|
|
333
|
+
basicSetup: {
|
|
334
|
+
lineNumbers: false,
|
|
335
|
+
foldGutter: false,
|
|
336
|
+
drawSelection: editable,
|
|
337
|
+
highlightActiveLine: editable,
|
|
338
|
+
highlightActiveLineGutter: editable,
|
|
339
|
+
highlightSelectionMatches: editable,
|
|
340
|
+
autocompletion: editable,
|
|
341
|
+
history: editable
|
|
342
|
+
},
|
|
343
|
+
indentWithTab: editable,
|
|
344
|
+
height,
|
|
345
|
+
minHeight,
|
|
346
|
+
maxHeight,
|
|
347
|
+
placeholder,
|
|
348
|
+
autoFocus
|
|
349
|
+
}
|
|
350
|
+
) }),
|
|
351
|
+
/* @__PURE__ */ jsx("span", { className: "fractal-code-block__status", "aria-live": "polite", children: copyStatus === "copied" ? "Code copied to clipboard." : copyStatus === "error" ? "Code could not be copied." : "" })
|
|
352
|
+
]
|
|
353
|
+
}
|
|
354
|
+
);
|
|
355
|
+
}
|
|
356
|
+
|
|
357
|
+
// src/components/Breadcrumbs/Breadcrumbs.tsx
|
|
358
|
+
import { ChevronRight } from "@mirror-physics/fractal-icons";
|
|
359
|
+
import { jsx as jsx2, jsxs as jsxs2 } from "react/jsx-runtime";
|
|
360
|
+
function Breadcrumbs({
|
|
361
|
+
items,
|
|
362
|
+
ariaLabel = "Breadcrumbs",
|
|
363
|
+
separator = /* @__PURE__ */ jsx2(ChevronRight, { "aria-hidden": "true", size: 14 }),
|
|
364
|
+
className,
|
|
365
|
+
...props
|
|
366
|
+
}) {
|
|
367
|
+
if (items.length === 0) return null;
|
|
368
|
+
return /* @__PURE__ */ jsx2("nav", { "aria-label": ariaLabel, className: cn("fractal-breadcrumbs", className), ...props, children: /* @__PURE__ */ jsx2("ol", { className: "fractal-breadcrumbs__list", children: items.map((item, index) => {
|
|
369
|
+
const isCurrent = index === items.length - 1;
|
|
370
|
+
const content = isCurrent ? /* @__PURE__ */ jsx2("span", { "aria-current": "page", className: "fractal-breadcrumbs__current", children: item.label }) : /* @__PURE__ */ jsx2("a", { className: "fractal-breadcrumbs__link", href: item.href ?? "#", onClick: item.onClick, children: item.label });
|
|
371
|
+
return /* @__PURE__ */ jsxs2("li", { className: "fractal-breadcrumbs__item", children: [
|
|
372
|
+
index > 0 && /* @__PURE__ */ jsx2("span", { "aria-hidden": "true", className: "fractal-breadcrumbs__separator", children: separator }),
|
|
373
|
+
content
|
|
374
|
+
] }, index);
|
|
375
|
+
}) }) });
|
|
376
|
+
}
|
|
167
377
|
|
|
168
378
|
// src/components/Card/Card.tsx
|
|
169
|
-
import * as
|
|
379
|
+
import * as React from "react";
|
|
170
380
|
import { Folder as FolderIcon } from "@mirror-physics/fractal-icons";
|
|
171
|
-
import { jsx, jsxs as
|
|
172
|
-
var Card =
|
|
173
|
-
({ className, ...props }, ref) => /* @__PURE__ */
|
|
381
|
+
import { jsx as jsx3, jsxs as jsxs3 } from "react/jsx-runtime";
|
|
382
|
+
var Card = React.forwardRef(
|
|
383
|
+
({ className, ...props }, ref) => /* @__PURE__ */ jsx3("div", { ref, "data-fractal-border-surface": "surface-1", className: cn("fractal-card", className), ...props })
|
|
174
384
|
);
|
|
175
385
|
Card.displayName = "Card";
|
|
176
|
-
var CardHeader =
|
|
177
|
-
({ className, ...props }, ref) => /* @__PURE__ */
|
|
386
|
+
var CardHeader = React.forwardRef(
|
|
387
|
+
({ className, ...props }, ref) => /* @__PURE__ */ jsx3("div", { ref, className: cn("fractal-card-header", className), ...props })
|
|
178
388
|
);
|
|
179
389
|
CardHeader.displayName = "CardHeader";
|
|
180
|
-
var CardTitle =
|
|
181
|
-
({ className, ...props }, ref) => /* @__PURE__ */
|
|
390
|
+
var CardTitle = React.forwardRef(
|
|
391
|
+
({ className, ...props }, ref) => /* @__PURE__ */ jsx3("h3", { ref, className: cn("fractal-card-title", className), ...props })
|
|
182
392
|
);
|
|
183
393
|
CardTitle.displayName = "CardTitle";
|
|
184
|
-
var CardDescription =
|
|
185
|
-
({ className, ...props }, ref) => /* @__PURE__ */
|
|
394
|
+
var CardDescription = React.forwardRef(
|
|
395
|
+
({ className, ...props }, ref) => /* @__PURE__ */ jsx3("p", { ref, className: cn("fractal-card-description", className), ...props })
|
|
186
396
|
);
|
|
187
397
|
CardDescription.displayName = "CardDescription";
|
|
188
|
-
var CardContent =
|
|
189
|
-
({ className, ...props }, ref) => /* @__PURE__ */
|
|
398
|
+
var CardContent = React.forwardRef(
|
|
399
|
+
({ className, ...props }, ref) => /* @__PURE__ */ jsx3("div", { ref, className: cn("fractal-card-content", className), ...props })
|
|
190
400
|
);
|
|
191
401
|
CardContent.displayName = "CardContent";
|
|
192
|
-
var CardFooter =
|
|
193
|
-
({ className, ...props }, ref) => /* @__PURE__ */
|
|
402
|
+
var CardFooter = React.forwardRef(
|
|
403
|
+
({ className, ...props }, ref) => /* @__PURE__ */ jsx3("div", { ref, className: cn("fractal-card-footer", className), ...props })
|
|
194
404
|
);
|
|
195
405
|
CardFooter.displayName = "CardFooter";
|
|
196
|
-
var FeatureCard =
|
|
197
|
-
({ icon, title, description, className, ...props }, ref) => /* @__PURE__ */
|
|
198
|
-
icon && /* @__PURE__ */
|
|
199
|
-
/* @__PURE__ */
|
|
200
|
-
/* @__PURE__ */
|
|
406
|
+
var FeatureCard = React.forwardRef(
|
|
407
|
+
({ icon, title, description, className, ...props }, ref) => /* @__PURE__ */ jsxs3("div", { ref, className: cn("fractal-feature-card", className), ...props, children: [
|
|
408
|
+
icon && /* @__PURE__ */ jsx3("div", { className: "fractal-feature-card__icon", children: icon }),
|
|
409
|
+
/* @__PURE__ */ jsx3("h3", { className: "fractal-feature-card__title", children: title }),
|
|
410
|
+
/* @__PURE__ */ jsx3("p", { className: "fractal-feature-card__description", children: description })
|
|
201
411
|
] })
|
|
202
412
|
);
|
|
203
413
|
FeatureCard.displayName = "FeatureCard";
|
|
204
|
-
var FolderCard =
|
|
205
|
-
({ name, sessionCount, selected, className, onClick, ...props }, ref) => /* @__PURE__ */
|
|
414
|
+
var FolderCard = React.forwardRef(
|
|
415
|
+
({ name, sessionCount, selected, className, onClick, ...props }, ref) => /* @__PURE__ */ jsxs3(
|
|
206
416
|
"div",
|
|
207
417
|
{
|
|
208
418
|
ref,
|
|
@@ -218,11 +428,11 @@ var FolderCard = React2.forwardRef(
|
|
|
218
428
|
className: cn("fractal-folder-card", selected && "fractal-folder-card--selected", className),
|
|
219
429
|
...props,
|
|
220
430
|
children: [
|
|
221
|
-
/* @__PURE__ */
|
|
222
|
-
/* @__PURE__ */
|
|
223
|
-
/* @__PURE__ */
|
|
431
|
+
/* @__PURE__ */ jsxs3("div", { className: "fractal-folder-card__header", children: [
|
|
432
|
+
/* @__PURE__ */ jsx3(FolderIcon, { size: 16, className: "fractal-folder-card__icon", "aria-hidden": true }),
|
|
433
|
+
/* @__PURE__ */ jsx3("span", { className: "fractal-folder-card__name", children: name })
|
|
224
434
|
] }),
|
|
225
|
-
sessionCount !== void 0 && /* @__PURE__ */
|
|
435
|
+
sessionCount !== void 0 && /* @__PURE__ */ jsx3("div", { className: "fractal-folder-card__footer", children: /* @__PURE__ */ jsxs3("span", { className: "fractal-folder-card__sessions", children: [
|
|
226
436
|
sessionCount,
|
|
227
437
|
" ",
|
|
228
438
|
sessionCount === 1 ? "session" : "sessions"
|
|
@@ -234,10 +444,10 @@ var FolderCard = React2.forwardRef(
|
|
|
234
444
|
FolderCard.displayName = "FolderCard";
|
|
235
445
|
|
|
236
446
|
// src/components/PromptCard/PromptCard.tsx
|
|
237
|
-
import * as
|
|
238
|
-
import { jsx as
|
|
447
|
+
import * as React2 from "react";
|
|
448
|
+
import { jsx as jsx4, jsxs as jsxs4 } from "react/jsx-runtime";
|
|
239
449
|
var titleToPrompt = (title) => typeof title === "string" || typeof title === "number" ? String(title) : "";
|
|
240
|
-
var PromptCard =
|
|
450
|
+
var PromptCard = React2.forwardRef(
|
|
241
451
|
({
|
|
242
452
|
title,
|
|
243
453
|
icon,
|
|
@@ -256,7 +466,7 @@ var PromptCard = React3.forwardRef(
|
|
|
256
466
|
onPromptSelect?.(prompt ?? titleToPrompt(title));
|
|
257
467
|
}
|
|
258
468
|
};
|
|
259
|
-
return /* @__PURE__ */
|
|
469
|
+
return /* @__PURE__ */ jsxs4(
|
|
260
470
|
"button",
|
|
261
471
|
{
|
|
262
472
|
ref,
|
|
@@ -271,16 +481,16 @@ var PromptCard = React3.forwardRef(
|
|
|
271
481
|
onClick: handleClick,
|
|
272
482
|
...props,
|
|
273
483
|
children: [
|
|
274
|
-
icon && /* @__PURE__ */
|
|
275
|
-
/* @__PURE__ */
|
|
484
|
+
icon && /* @__PURE__ */ jsx4("span", { className: "fractal-prompt-card__icon", "aria-hidden": "true", children: icon }),
|
|
485
|
+
/* @__PURE__ */ jsx4("span", { className: "fractal-prompt-card__title", children: title })
|
|
276
486
|
]
|
|
277
487
|
}
|
|
278
488
|
);
|
|
279
489
|
}
|
|
280
490
|
);
|
|
281
491
|
PromptCard.displayName = "PromptCard";
|
|
282
|
-
var PromptGrid =
|
|
283
|
-
({ compact, padded, className, ...props }, ref) => /* @__PURE__ */
|
|
492
|
+
var PromptGrid = React2.forwardRef(
|
|
493
|
+
({ compact, padded, className, ...props }, ref) => /* @__PURE__ */ jsx4(
|
|
284
494
|
"div",
|
|
285
495
|
{
|
|
286
496
|
ref,
|
|
@@ -297,29 +507,365 @@ var PromptGrid = React3.forwardRef(
|
|
|
297
507
|
PromptGrid.displayName = "PromptGrid";
|
|
298
508
|
|
|
299
509
|
// src/components/Input/Input.tsx
|
|
510
|
+
import * as React3 from "react";
|
|
511
|
+
|
|
512
|
+
// src/utils/FloatingFieldBorder.tsx
|
|
513
|
+
import { jsx as jsx5 } from "react/jsx-runtime";
|
|
514
|
+
function FloatingFieldBorder({ label }) {
|
|
515
|
+
return /* @__PURE__ */ jsx5("fieldset", { className: "fractal-floating-field__border", "aria-hidden": "true", children: /* @__PURE__ */ jsx5("legend", { children: /* @__PURE__ */ jsx5("span", { children: label }) }) });
|
|
516
|
+
}
|
|
517
|
+
|
|
518
|
+
// src/components/Input/Input.tsx
|
|
519
|
+
import { jsx as jsx6, jsxs as jsxs5 } from "react/jsx-runtime";
|
|
520
|
+
var Input = React3.forwardRef(
|
|
521
|
+
({ className, type, controlSize = "lg", fieldLabel, id, placeholder, ...props }, ref) => {
|
|
522
|
+
const generatedId = React3.useId();
|
|
523
|
+
const fieldId = id ?? generatedId;
|
|
524
|
+
const floatingLabel = type === "search" ? void 0 : fieldLabel;
|
|
525
|
+
const input = /* @__PURE__ */ jsx6(
|
|
526
|
+
"input",
|
|
527
|
+
{
|
|
528
|
+
type,
|
|
529
|
+
ref,
|
|
530
|
+
id: floatingLabel ? fieldId : id,
|
|
531
|
+
placeholder: floatingLabel ? placeholder || " " : placeholder,
|
|
532
|
+
"data-control-size": controlSize,
|
|
533
|
+
className: cn("fractal-control", "fractal-input", className),
|
|
534
|
+
...props,
|
|
535
|
+
"aria-label": props["aria-label"] ?? (type === "search" && !props["aria-labelledby"] ? fieldLabel ?? "Search" : void 0)
|
|
536
|
+
}
|
|
537
|
+
);
|
|
538
|
+
if (!floatingLabel) return input;
|
|
539
|
+
return /* @__PURE__ */ jsxs5(
|
|
540
|
+
"div",
|
|
541
|
+
{
|
|
542
|
+
className: "fractal-floating-field",
|
|
543
|
+
"data-control-size": controlSize,
|
|
544
|
+
"data-always-float": ["date", "datetime-local", "time", "month", "week", "color", "file", "range"].includes(type ?? "") || void 0,
|
|
545
|
+
children: [
|
|
546
|
+
input,
|
|
547
|
+
/* @__PURE__ */ jsx6(FloatingFieldBorder, { label: fieldLabel ?? "" }),
|
|
548
|
+
/* @__PURE__ */ jsx6("label", { className: "fractal-floating-field__label", htmlFor: fieldId, children: fieldLabel })
|
|
549
|
+
]
|
|
550
|
+
}
|
|
551
|
+
);
|
|
552
|
+
}
|
|
553
|
+
);
|
|
554
|
+
Input.displayName = "Input";
|
|
555
|
+
|
|
556
|
+
// src/components/TableSearch/TableSearch.tsx
|
|
300
557
|
import * as React4 from "react";
|
|
301
|
-
import {
|
|
302
|
-
|
|
303
|
-
|
|
304
|
-
|
|
558
|
+
import { MagnifyingGlass, MagnifyingGlassLines } from "@mirror-physics/fractal-icons";
|
|
559
|
+
import { jsx as jsx7, jsxs as jsxs6 } from "react/jsx-runtime";
|
|
560
|
+
var TableSearch = React4.forwardRef(
|
|
561
|
+
({
|
|
562
|
+
searchType = "text",
|
|
563
|
+
controlSize = "lg",
|
|
564
|
+
className,
|
|
565
|
+
inputClassName,
|
|
566
|
+
placeholder,
|
|
567
|
+
title,
|
|
568
|
+
...props
|
|
569
|
+
}, ref) => {
|
|
570
|
+
const isGlob = searchType === "glob";
|
|
571
|
+
const SearchIcon = isGlob ? MagnifyingGlassLines : MagnifyingGlass;
|
|
572
|
+
return /* @__PURE__ */ jsxs6(
|
|
573
|
+
"div",
|
|
574
|
+
{
|
|
575
|
+
className: cn("fractal-table-search", className),
|
|
576
|
+
"data-search-type": searchType,
|
|
577
|
+
"data-control-size": controlSize,
|
|
578
|
+
children: [
|
|
579
|
+
/* @__PURE__ */ jsx7(SearchIcon, { className: "fractal-table-search__icon", size: 17, "aria-hidden": "true" }),
|
|
580
|
+
/* @__PURE__ */ jsx7(
|
|
581
|
+
Input,
|
|
582
|
+
{
|
|
583
|
+
...props,
|
|
584
|
+
controlSize,
|
|
585
|
+
ref,
|
|
586
|
+
type: "search",
|
|
587
|
+
className: cn("fractal-table-search__input", inputClassName),
|
|
588
|
+
placeholder: placeholder ?? (isGlob ? "Glob search \u2014 use *, ?, or [a-z]" : "Search"),
|
|
589
|
+
title: title ?? (isGlob ? "Glob pattern: *, **, ?, [abc], [a-z], and [!abc]" : void 0)
|
|
590
|
+
}
|
|
591
|
+
)
|
|
592
|
+
]
|
|
593
|
+
}
|
|
594
|
+
);
|
|
595
|
+
}
|
|
596
|
+
);
|
|
597
|
+
TableSearch.displayName = "TableSearch";
|
|
598
|
+
|
|
599
|
+
// src/components/NumberInput/NumberInput.tsx
|
|
600
|
+
import * as React5 from "react";
|
|
601
|
+
import { Minus, Plus } from "@mirror-physics/fractal-icons";
|
|
602
|
+
import { jsx as jsx8, jsxs as jsxs7 } from "react/jsx-runtime";
|
|
603
|
+
function NumberInput({
|
|
604
|
+
unit,
|
|
605
|
+
controlSize = "lg",
|
|
606
|
+
className,
|
|
607
|
+
value,
|
|
608
|
+
defaultValue,
|
|
609
|
+
disabled,
|
|
610
|
+
readOnly,
|
|
611
|
+
min,
|
|
612
|
+
max,
|
|
613
|
+
...props
|
|
614
|
+
}) {
|
|
615
|
+
const inputRef = React5.useRef(null);
|
|
616
|
+
const numericValue = Number(value ?? defaultValue);
|
|
617
|
+
const characterCount = Math.max(String(value ?? defaultValue ?? "").length, 1);
|
|
618
|
+
const controlLabel = typeof props["aria-label"] === "string" ? props["aria-label"] : props.fieldLabel ?? "value";
|
|
619
|
+
const decrementDisabled = disabled || readOnly || Number.isFinite(numericValue) && min !== void 0 && numericValue <= Number(min);
|
|
620
|
+
const incrementDisabled = disabled || readOnly || Number.isFinite(numericValue) && max !== void 0 && numericValue >= Number(max);
|
|
621
|
+
const changeByStep = (direction) => {
|
|
622
|
+
const input = inputRef.current;
|
|
623
|
+
if (!input) return;
|
|
624
|
+
if (direction === -1) input.stepDown();
|
|
625
|
+
else input.stepUp();
|
|
626
|
+
input.dispatchEvent(new Event("input", { bubbles: true }));
|
|
627
|
+
input.focus();
|
|
628
|
+
};
|
|
629
|
+
return /* @__PURE__ */ jsxs7("div", { "data-control-size": controlSize, className: cn("fractal-number-input", unit && "fractal-number-input--with-unit", className), children: [
|
|
630
|
+
/* @__PURE__ */ jsx8(
|
|
631
|
+
Input,
|
|
632
|
+
{
|
|
633
|
+
ref: inputRef,
|
|
634
|
+
controlSize,
|
|
635
|
+
type: "number",
|
|
636
|
+
value,
|
|
637
|
+
defaultValue,
|
|
638
|
+
disabled,
|
|
639
|
+
readOnly,
|
|
640
|
+
min,
|
|
641
|
+
max,
|
|
642
|
+
...props
|
|
643
|
+
}
|
|
644
|
+
),
|
|
645
|
+
unit && /* @__PURE__ */ jsx8(
|
|
646
|
+
"span",
|
|
647
|
+
{
|
|
648
|
+
className: "fractal-number-input-unit",
|
|
649
|
+
style: { left: `calc(var(--control-padding-inline) + ${characterCount}ch)` },
|
|
650
|
+
"aria-hidden": "true",
|
|
651
|
+
children: unit
|
|
652
|
+
}
|
|
653
|
+
),
|
|
654
|
+
/* @__PURE__ */ jsxs7("div", { className: "fractal-number-input-controls", children: [
|
|
655
|
+
/* @__PURE__ */ jsx8(
|
|
656
|
+
"button",
|
|
657
|
+
{
|
|
658
|
+
type: "button",
|
|
659
|
+
className: "fractal-number-input-step",
|
|
660
|
+
"aria-label": `Decrease ${controlLabel}`,
|
|
661
|
+
disabled: decrementDisabled,
|
|
662
|
+
onClick: () => changeByStep(-1),
|
|
663
|
+
children: /* @__PURE__ */ jsx8(Minus, { "aria-hidden": "true", size: 16 })
|
|
664
|
+
}
|
|
665
|
+
),
|
|
666
|
+
/* @__PURE__ */ jsx8(
|
|
667
|
+
"button",
|
|
668
|
+
{
|
|
669
|
+
type: "button",
|
|
670
|
+
className: "fractal-number-input-step",
|
|
671
|
+
"aria-label": `Increase ${controlLabel}`,
|
|
672
|
+
disabled: incrementDisabled,
|
|
673
|
+
onClick: () => changeByStep(1),
|
|
674
|
+
children: /* @__PURE__ */ jsx8(Plus, { "aria-hidden": "true", size: 16 })
|
|
675
|
+
}
|
|
676
|
+
)
|
|
677
|
+
] })
|
|
678
|
+
] });
|
|
679
|
+
}
|
|
680
|
+
|
|
681
|
+
// src/components/Slider/Slider.tsx
|
|
682
|
+
import { jsx as jsx9, jsxs as jsxs8 } from "react/jsx-runtime";
|
|
683
|
+
function Slider(props) {
|
|
684
|
+
const {
|
|
685
|
+
min = 0,
|
|
686
|
+
max = 100,
|
|
687
|
+
step = 1,
|
|
688
|
+
disabled = false,
|
|
689
|
+
className,
|
|
690
|
+
showValues = true,
|
|
691
|
+
formatValue = (value) => value,
|
|
692
|
+
knobs = 1
|
|
693
|
+
} = props;
|
|
694
|
+
const span = Math.max(max - min, 1);
|
|
695
|
+
const rawValues = knobs === 2 ? props.value : [props.value];
|
|
696
|
+
const firstValue = clamp(rawValues[0], min, max);
|
|
697
|
+
const secondValue = knobs === 2 ? clamp(rawValues[1], firstValue, max) : firstValue;
|
|
698
|
+
const selectionStart = knobs === 2 ? firstValue : min;
|
|
699
|
+
const selectionEnd = secondValue;
|
|
700
|
+
const selectionStartPercent = (selectionStart - min) / span * 100;
|
|
701
|
+
const selectionEndPercent = (selectionEnd - min) / span * 100;
|
|
702
|
+
const changeSingleValue = (value) => {
|
|
703
|
+
;
|
|
704
|
+
props.onValueChange(clamp(value, min, max));
|
|
705
|
+
};
|
|
706
|
+
const changeRangeValue = (nextLower, nextUpper) => {
|
|
707
|
+
;
|
|
708
|
+
props.onValueChange([
|
|
709
|
+
clamp(nextLower, min, nextUpper),
|
|
710
|
+
clamp(nextUpper, nextLower, max)
|
|
711
|
+
]);
|
|
712
|
+
};
|
|
713
|
+
const getKeyboardValue = (event, value) => {
|
|
714
|
+
const pageStep = step * 10;
|
|
715
|
+
const adjustments = {
|
|
716
|
+
ArrowDown: -step,
|
|
717
|
+
ArrowLeft: -step,
|
|
718
|
+
ArrowRight: step,
|
|
719
|
+
ArrowUp: step,
|
|
720
|
+
PageDown: -pageStep,
|
|
721
|
+
PageUp: pageStep
|
|
722
|
+
};
|
|
723
|
+
if (event.key === "Home") return min;
|
|
724
|
+
if (event.key === "End") return max;
|
|
725
|
+
if (!(event.key in adjustments)) return null;
|
|
726
|
+
return value + adjustments[event.key];
|
|
727
|
+
};
|
|
728
|
+
return /* @__PURE__ */ jsxs8(
|
|
729
|
+
"div",
|
|
305
730
|
{
|
|
306
|
-
|
|
307
|
-
|
|
308
|
-
|
|
309
|
-
|
|
731
|
+
className: cn("fractal-slider", disabled && "fractal-slider--disabled", className),
|
|
732
|
+
"data-disabled": disabled || void 0,
|
|
733
|
+
"data-knobs": knobs,
|
|
734
|
+
children: [
|
|
735
|
+
showValues && /* @__PURE__ */ jsxs8("div", { className: "fractal-slider-values", "aria-hidden": "true", children: [
|
|
736
|
+
/* @__PURE__ */ jsx9("output", { children: formatValue(firstValue) }),
|
|
737
|
+
knobs === 2 && /* @__PURE__ */ jsx9("output", { children: formatValue(secondValue) })
|
|
738
|
+
] }),
|
|
739
|
+
/* @__PURE__ */ jsxs8(
|
|
740
|
+
"div",
|
|
741
|
+
{
|
|
742
|
+
className: "fractal-slider-control",
|
|
743
|
+
style: {
|
|
744
|
+
"--fractal-slider-selection-start": `${selectionStartPercent}%`,
|
|
745
|
+
"--fractal-slider-selection-end": `${selectionEndPercent}%`
|
|
746
|
+
},
|
|
747
|
+
children: [
|
|
748
|
+
/* @__PURE__ */ jsx9("span", { className: "fractal-slider-track", "aria-hidden": "true" }),
|
|
749
|
+
/* @__PURE__ */ jsx9("span", { className: "fractal-slider-selection", "aria-hidden": "true" }),
|
|
750
|
+
/* @__PURE__ */ jsx9(
|
|
751
|
+
"input",
|
|
752
|
+
{
|
|
753
|
+
"aria-label": knobs === 2 ? props.lowerAriaLabel ?? "Lower value" : props.ariaLabel ?? "Slider value",
|
|
754
|
+
disabled,
|
|
755
|
+
max,
|
|
756
|
+
min,
|
|
757
|
+
onChange: (event) => {
|
|
758
|
+
const nextValue = event.currentTarget.valueAsNumber;
|
|
759
|
+
if (knobs === 2) changeRangeValue(Math.min(nextValue, secondValue), secondValue);
|
|
760
|
+
else changeSingleValue(nextValue);
|
|
761
|
+
},
|
|
762
|
+
onKeyDown: (event) => {
|
|
763
|
+
const nextValue = getKeyboardValue(event, firstValue);
|
|
764
|
+
if (nextValue === null) return;
|
|
765
|
+
event.preventDefault();
|
|
766
|
+
if (knobs === 2) changeRangeValue(Math.min(nextValue, secondValue), secondValue);
|
|
767
|
+
else changeSingleValue(nextValue);
|
|
768
|
+
},
|
|
769
|
+
step,
|
|
770
|
+
type: "range",
|
|
771
|
+
value: firstValue
|
|
772
|
+
}
|
|
773
|
+
),
|
|
774
|
+
knobs === 2 && /* @__PURE__ */ jsx9(
|
|
775
|
+
"input",
|
|
776
|
+
{
|
|
777
|
+
"aria-label": props.upperAriaLabel ?? "Upper value",
|
|
778
|
+
disabled,
|
|
779
|
+
max,
|
|
780
|
+
min,
|
|
781
|
+
onChange: (event) => {
|
|
782
|
+
const nextValue = event.currentTarget.valueAsNumber;
|
|
783
|
+
changeRangeValue(firstValue, Math.max(nextValue, firstValue));
|
|
784
|
+
},
|
|
785
|
+
onKeyDown: (event) => {
|
|
786
|
+
const nextValue = getKeyboardValue(event, secondValue);
|
|
787
|
+
if (nextValue === null) return;
|
|
788
|
+
event.preventDefault();
|
|
789
|
+
changeRangeValue(firstValue, Math.max(nextValue, firstValue));
|
|
790
|
+
},
|
|
791
|
+
step,
|
|
792
|
+
type: "range",
|
|
793
|
+
value: secondValue
|
|
794
|
+
}
|
|
795
|
+
)
|
|
796
|
+
]
|
|
797
|
+
}
|
|
798
|
+
)
|
|
799
|
+
]
|
|
310
800
|
}
|
|
311
|
-
)
|
|
801
|
+
);
|
|
802
|
+
}
|
|
803
|
+
function clamp(value, minimum, maximum) {
|
|
804
|
+
return Math.min(maximum, Math.max(minimum, value));
|
|
805
|
+
}
|
|
806
|
+
|
|
807
|
+
// src/components/PasswordInput/PasswordInput.tsx
|
|
808
|
+
import * as React6 from "react";
|
|
809
|
+
import { Eye, EyeSlash } from "@mirror-physics/fractal-icons";
|
|
810
|
+
import { jsx as jsx10, jsxs as jsxs9 } from "react/jsx-runtime";
|
|
811
|
+
var PasswordInput = React6.forwardRef(
|
|
812
|
+
({
|
|
813
|
+
className,
|
|
814
|
+
controlSize = "lg",
|
|
815
|
+
disabled,
|
|
816
|
+
showPasswordLabel = "Show password",
|
|
817
|
+
hidePasswordLabel = "Hide password",
|
|
818
|
+
...props
|
|
819
|
+
}, ref) => {
|
|
820
|
+
const [passwordVisible, setPasswordVisible] = React6.useState(false);
|
|
821
|
+
const toggleLabel = passwordVisible ? hidePasswordLabel : showPasswordLabel;
|
|
822
|
+
return /* @__PURE__ */ jsxs9(
|
|
823
|
+
"div",
|
|
824
|
+
{
|
|
825
|
+
className: cn("fractal-password-input", className),
|
|
826
|
+
"data-control-size": controlSize,
|
|
827
|
+
"data-password-visible": passwordVisible ? "" : void 0,
|
|
828
|
+
children: [
|
|
829
|
+
/* @__PURE__ */ jsx10(
|
|
830
|
+
Input,
|
|
831
|
+
{
|
|
832
|
+
...props,
|
|
833
|
+
controlSize,
|
|
834
|
+
ref,
|
|
835
|
+
className: "fractal-password-input-field",
|
|
836
|
+
disabled,
|
|
837
|
+
type: passwordVisible ? "text" : "password"
|
|
838
|
+
}
|
|
839
|
+
),
|
|
840
|
+
/* @__PURE__ */ jsx10(
|
|
841
|
+
"button",
|
|
842
|
+
{
|
|
843
|
+
type: "button",
|
|
844
|
+
className: "fractal-password-input-toggle",
|
|
845
|
+
"aria-label": toggleLabel,
|
|
846
|
+
"aria-pressed": passwordVisible,
|
|
847
|
+
disabled,
|
|
848
|
+
title: toggleLabel,
|
|
849
|
+
onClick: () => setPasswordVisible((visible) => !visible),
|
|
850
|
+
children: passwordVisible ? /* @__PURE__ */ jsx10(EyeSlash, { "aria-hidden": "true", size: 18 }) : /* @__PURE__ */ jsx10(Eye, { "aria-hidden": "true", size: 18 })
|
|
851
|
+
}
|
|
852
|
+
)
|
|
853
|
+
]
|
|
854
|
+
}
|
|
855
|
+
);
|
|
856
|
+
}
|
|
312
857
|
);
|
|
313
|
-
|
|
858
|
+
PasswordInput.displayName = "PasswordInput";
|
|
314
859
|
|
|
315
860
|
// src/components/Label/Label.tsx
|
|
316
|
-
import * as
|
|
317
|
-
import { jsx as
|
|
318
|
-
var Label =
|
|
319
|
-
({ className, ...props }, ref) => /* @__PURE__ */
|
|
861
|
+
import * as React7 from "react";
|
|
862
|
+
import { jsx as jsx11 } from "react/jsx-runtime";
|
|
863
|
+
var Label = React7.forwardRef(
|
|
864
|
+
({ className, controlSize = "lg", ...props }, ref) => /* @__PURE__ */ jsx11(
|
|
320
865
|
"label",
|
|
321
866
|
{
|
|
322
867
|
ref,
|
|
868
|
+
"data-control-size": controlSize,
|
|
323
869
|
className: cn("fractal-label", className),
|
|
324
870
|
...props
|
|
325
871
|
}
|
|
@@ -328,44 +874,147 @@ var Label = React5.forwardRef(
|
|
|
328
874
|
Label.displayName = "Label";
|
|
329
875
|
|
|
330
876
|
// src/components/Alert/Alert.tsx
|
|
331
|
-
import * as
|
|
332
|
-
import {
|
|
877
|
+
import * as React8 from "react";
|
|
878
|
+
import { CircleCheck, CircleClose, CircleInfo, Warning } from "@mirror-physics/fractal-icons";
|
|
879
|
+
import { jsx as jsx12, jsxs as jsxs10 } from "react/jsx-runtime";
|
|
333
880
|
var defaultIcons = {
|
|
334
|
-
default:
|
|
335
|
-
info:
|
|
336
|
-
success:
|
|
337
|
-
warning:
|
|
338
|
-
error:
|
|
881
|
+
default: CircleInfo,
|
|
882
|
+
info: CircleInfo,
|
|
883
|
+
success: CircleCheck,
|
|
884
|
+
warning: Warning,
|
|
885
|
+
error: CircleClose
|
|
886
|
+
};
|
|
887
|
+
var Alert = React8.forwardRef(
|
|
888
|
+
({ className, variant = "default", icon, children, ...props }, ref) => {
|
|
889
|
+
const DefaultIcon = defaultIcons[variant];
|
|
890
|
+
return /* @__PURE__ */ jsxs10(
|
|
891
|
+
"div",
|
|
892
|
+
{
|
|
893
|
+
ref,
|
|
894
|
+
role: "alert",
|
|
895
|
+
className: cn("fractal-alert", `fractal-alert--${variant}`, className),
|
|
896
|
+
...props,
|
|
897
|
+
children: [
|
|
898
|
+
/* @__PURE__ */ jsx12("span", { className: "fractal-alert-icon", "aria-hidden": true, children: icon ?? /* @__PURE__ */ jsx12(DefaultIcon, { size: 18 }) }),
|
|
899
|
+
/* @__PURE__ */ jsx12("div", { className: "fractal-alert-content", children })
|
|
900
|
+
]
|
|
901
|
+
}
|
|
902
|
+
);
|
|
903
|
+
}
|
|
904
|
+
);
|
|
905
|
+
Alert.displayName = "Alert";
|
|
906
|
+
var AlertTitle = React8.forwardRef(
|
|
907
|
+
({ className, ...props }, ref) => /* @__PURE__ */ jsx12("h5", { ref, className: cn("fractal-alert-title", className), ...props })
|
|
908
|
+
);
|
|
909
|
+
AlertTitle.displayName = "AlertTitle";
|
|
910
|
+
var AlertDescription = React8.forwardRef(
|
|
911
|
+
({ className, ...props }, ref) => /* @__PURE__ */ jsx12("div", { ref, className: cn("fractal-alert-description", className), ...props })
|
|
912
|
+
);
|
|
913
|
+
AlertDescription.displayName = "AlertDescription";
|
|
914
|
+
|
|
915
|
+
// src/components/Toast/Toast.tsx
|
|
916
|
+
import * as React9 from "react";
|
|
917
|
+
import { createPortal } from "react-dom";
|
|
918
|
+
import { CircleCheck as CircleCheck2, CircleClose as CircleClose2, CircleInfo as CircleInfo2, Close, Warning as Warning2 } from "@mirror-physics/fractal-icons";
|
|
919
|
+
import { jsx as jsx13, jsxs as jsxs11 } from "react/jsx-runtime";
|
|
920
|
+
var defaultIcons2 = {
|
|
921
|
+
default: CircleInfo2,
|
|
922
|
+
info: CircleInfo2,
|
|
923
|
+
success: CircleCheck2,
|
|
924
|
+
warning: Warning2,
|
|
925
|
+
error: CircleClose2
|
|
339
926
|
};
|
|
340
|
-
var
|
|
341
|
-
|
|
927
|
+
var Toast = React9.forwardRef(function Toast2({
|
|
928
|
+
action,
|
|
929
|
+
children,
|
|
930
|
+
className,
|
|
931
|
+
dismissLabel = "Dismiss notification",
|
|
932
|
+
duration,
|
|
933
|
+
icon,
|
|
934
|
+
onBlurCapture,
|
|
935
|
+
onDismiss,
|
|
936
|
+
onFocusCapture,
|
|
937
|
+
onPointerEnter,
|
|
938
|
+
onPointerLeave,
|
|
939
|
+
role,
|
|
940
|
+
variant = "default",
|
|
941
|
+
...props
|
|
942
|
+
}, ref) {
|
|
943
|
+
const [paused, setPaused] = React9.useState(false);
|
|
944
|
+
const dismissRef = React9.useRef(onDismiss);
|
|
945
|
+
const DefaultIcon = defaultIcons2[variant];
|
|
946
|
+
const resolvedDuration = duration === void 0 ? variant === "error" ? null : 5e3 : duration;
|
|
947
|
+
React9.useEffect(() => {
|
|
948
|
+
dismissRef.current = onDismiss;
|
|
949
|
+
}, [onDismiss]);
|
|
950
|
+
React9.useEffect(() => {
|
|
951
|
+
if (!dismissRef.current || paused || resolvedDuration === null || resolvedDuration <= 0) return;
|
|
952
|
+
const timeout = window.setTimeout(() => dismissRef.current?.(), resolvedDuration);
|
|
953
|
+
return () => window.clearTimeout(timeout);
|
|
954
|
+
}, [paused, resolvedDuration]);
|
|
955
|
+
const announcementRole = role ?? (variant === "error" ? "alert" : "status");
|
|
956
|
+
return /* @__PURE__ */ jsxs11(
|
|
342
957
|
"div",
|
|
343
958
|
{
|
|
344
959
|
ref,
|
|
345
|
-
|
|
346
|
-
|
|
960
|
+
"aria-atomic": "true",
|
|
961
|
+
"aria-live": announcementRole === "alert" ? "assertive" : "polite",
|
|
962
|
+
className: cn("fractal-toast", `fractal-toast--${variant}`, className),
|
|
963
|
+
role: announcementRole,
|
|
964
|
+
onBlurCapture: (event) => {
|
|
965
|
+
onBlurCapture?.(event);
|
|
966
|
+
if (!event.currentTarget.contains(event.relatedTarget)) setPaused(false);
|
|
967
|
+
},
|
|
968
|
+
onFocusCapture: (event) => {
|
|
969
|
+
onFocusCapture?.(event);
|
|
970
|
+
setPaused(true);
|
|
971
|
+
},
|
|
972
|
+
onPointerEnter: (event) => {
|
|
973
|
+
onPointerEnter?.(event);
|
|
974
|
+
setPaused(true);
|
|
975
|
+
},
|
|
976
|
+
onPointerLeave: (event) => {
|
|
977
|
+
onPointerLeave?.(event);
|
|
978
|
+
setPaused(false);
|
|
979
|
+
},
|
|
347
980
|
...props,
|
|
348
981
|
children: [
|
|
349
|
-
/* @__PURE__ */
|
|
350
|
-
/* @__PURE__ */
|
|
982
|
+
/* @__PURE__ */ jsx13("span", { "aria-hidden": "true", className: "fractal-toast__icon", children: icon ?? /* @__PURE__ */ jsx13(DefaultIcon, { size: 18 }) }),
|
|
983
|
+
/* @__PURE__ */ jsx13("div", { className: "fractal-toast__content", children }),
|
|
984
|
+
action && /* @__PURE__ */ jsx13("div", { className: "fractal-toast__action", children: action }),
|
|
985
|
+
/* @__PURE__ */ jsx13(
|
|
986
|
+
"button",
|
|
987
|
+
{
|
|
988
|
+
"aria-label": dismissLabel,
|
|
989
|
+
className: "fractal-toast__dismiss",
|
|
990
|
+
onClick: onDismiss,
|
|
991
|
+
type: "button",
|
|
992
|
+
children: /* @__PURE__ */ jsx13(Close, { "aria-hidden": "true", size: 14 })
|
|
993
|
+
}
|
|
994
|
+
)
|
|
351
995
|
]
|
|
352
996
|
}
|
|
353
|
-
)
|
|
354
|
-
);
|
|
355
|
-
|
|
356
|
-
|
|
357
|
-
|
|
358
|
-
|
|
359
|
-
|
|
360
|
-
|
|
361
|
-
|
|
362
|
-
|
|
363
|
-
|
|
997
|
+
);
|
|
998
|
+
});
|
|
999
|
+
var ToastViewport = React9.forwardRef(function ToastViewport2({ children, className, portal = true, position = "top-center", ...props }, ref) {
|
|
1000
|
+
const viewport = /* @__PURE__ */ jsx13(
|
|
1001
|
+
"div",
|
|
1002
|
+
{
|
|
1003
|
+
ref,
|
|
1004
|
+
className: cn("fractal-toast-viewport", `fractal-toast-viewport--${position}`, className),
|
|
1005
|
+
"data-position": position,
|
|
1006
|
+
...props,
|
|
1007
|
+
children
|
|
1008
|
+
}
|
|
1009
|
+
);
|
|
1010
|
+
if (!portal || typeof document === "undefined") return viewport;
|
|
1011
|
+
return createPortal(viewport, document.body);
|
|
1012
|
+
});
|
|
364
1013
|
|
|
365
1014
|
// src/components/Toggle/Toggle.tsx
|
|
366
|
-
import { jsx as
|
|
1015
|
+
import { jsx as jsx14, jsxs as jsxs12 } from "react/jsx-runtime";
|
|
367
1016
|
function Toggle({ checked, onChange, label, className }) {
|
|
368
|
-
return /* @__PURE__ */
|
|
1017
|
+
return /* @__PURE__ */ jsxs12(
|
|
369
1018
|
"button",
|
|
370
1019
|
{
|
|
371
1020
|
type: "button",
|
|
@@ -374,18 +1023,19 @@ function Toggle({ checked, onChange, label, className }) {
|
|
|
374
1023
|
className: cn("fractal-toggle", className),
|
|
375
1024
|
onClick: () => onChange(!checked),
|
|
376
1025
|
children: [
|
|
377
|
-
/* @__PURE__ */
|
|
378
|
-
label && /* @__PURE__ */
|
|
1026
|
+
/* @__PURE__ */ jsx14("span", { className: cn("fractal-toggle-track", checked && "fractal-toggle-track--checked"), children: /* @__PURE__ */ jsx14("span", { className: cn("fractal-toggle-thumb", checked && "fractal-toggle-thumb--checked") }) }),
|
|
1027
|
+
label && /* @__PURE__ */ jsx14("span", { className: "fractal-toggle-label", children: label })
|
|
379
1028
|
]
|
|
380
1029
|
}
|
|
381
1030
|
);
|
|
382
1031
|
}
|
|
383
1032
|
|
|
384
1033
|
// src/components/Modal/Modal.tsx
|
|
385
|
-
import
|
|
1034
|
+
import * as React10 from "react";
|
|
1035
|
+
import { createPortal as createPortal2 } from "react-dom";
|
|
386
1036
|
|
|
387
1037
|
// src/hooks/useEscapeDismiss.ts
|
|
388
|
-
import { useEffect, useRef } from "react";
|
|
1038
|
+
import { useEffect as useEffect3, useRef as useRef4 } from "react";
|
|
389
1039
|
var nextId = 0;
|
|
390
1040
|
var stack = [];
|
|
391
1041
|
function insertSorted(entry) {
|
|
@@ -418,9 +1068,9 @@ function ensureGlobalListener() {
|
|
|
418
1068
|
);
|
|
419
1069
|
}
|
|
420
1070
|
function useEscapeDismiss(priority, handler, enabled = true) {
|
|
421
|
-
const handlerRef =
|
|
1071
|
+
const handlerRef = useRef4(handler);
|
|
422
1072
|
handlerRef.current = handler;
|
|
423
|
-
|
|
1073
|
+
useEffect3(() => {
|
|
424
1074
|
if (!enabled) return;
|
|
425
1075
|
ensureGlobalListener();
|
|
426
1076
|
const id = nextId++;
|
|
@@ -434,27 +1084,99 @@ function useEscapeDismiss(priority, handler, enabled = true) {
|
|
|
434
1084
|
}, [priority, enabled]);
|
|
435
1085
|
}
|
|
436
1086
|
|
|
1087
|
+
// src/components/UILoader/UILoader.tsx
|
|
1088
|
+
import { useId as useId2 } from "react";
|
|
1089
|
+
import { jsx as jsx15, jsxs as jsxs13 } from "react/jsx-runtime";
|
|
1090
|
+
var LEFT = "M0 53C0 51 1.6 49.5 3.6 49.5h16.5c1 0 1.9.4 2.5 1L42.1 69.6c.7.7 1.1 1.6 1.1 2.5v16.2c0 2-1.6 3.5-3.6 3.5H23.1c-1 0-1.9-.4-2.5-1L1.1 71.7C.4 71 0 70.1 0 69.2V53Z";
|
|
1091
|
+
var CENTER = "M0 3.5C0 1.6 1.6 0 3.6 0h16.5c1 0 1.9.4 2.5 1L92.5 69.6c.7.7 1 1.6 1 2.5v16.2c0 2-1.6 3.5-3.6 3.5H73.4c-1 0-1.9-.4-2.5-1L1.1 22.2C.4 21.6 0 20.7 0 19.7V3.5Z";
|
|
1092
|
+
var RIGHT = "M50.4 3.5C50.4 1.6 52 0 54 0h16.5c1 0 1.9.4 2.5 1l69.8 68.6c.7.7 1.1 1.6 1.1 2.5v16.2c0 2-1.6 3.5-3.6 3.5h-16.5c-1 0-1.9-.4-2.5-1L51.4 22.2c-.7-.6-1-1.5-1-2.5V3.5Z";
|
|
1093
|
+
function UILoader({ size = 48, tone = "neutral", className, style, label = "Loading", ariaHidden = false }) {
|
|
1094
|
+
const rawId = useId2().replace(/[^a-zA-Z0-9_-]/g, "");
|
|
1095
|
+
const clipId = `fractal-ui-loader-clip-${rawId}`;
|
|
1096
|
+
const gradientId = `fractal-ui-loader-gradient-${rawId}`;
|
|
1097
|
+
const height = typeof size === "number" ? `${size}px` : size;
|
|
1098
|
+
return /* @__PURE__ */ jsx15(
|
|
1099
|
+
"span",
|
|
1100
|
+
{
|
|
1101
|
+
"aria-hidden": ariaHidden || void 0,
|
|
1102
|
+
"aria-label": ariaHidden ? void 0 : label,
|
|
1103
|
+
className: cn("fractal-ui-loader", `fractal-ui-loader--${tone}`, className),
|
|
1104
|
+
role: ariaHidden ? void 0 : "status",
|
|
1105
|
+
style,
|
|
1106
|
+
children: /* @__PURE__ */ jsxs13("svg", { "aria-hidden": "true", fill: "none", viewBox: "0 0 144 92", style: { height, width: "auto" }, children: [
|
|
1107
|
+
/* @__PURE__ */ jsxs13("defs", { children: [
|
|
1108
|
+
/* @__PURE__ */ jsxs13("linearGradient", { id: gradientId, x1: "59", x2: "94.3", y1: "0", y2: "89.1", gradientUnits: "userSpaceOnUse", children: [
|
|
1109
|
+
/* @__PURE__ */ jsx15("stop", { className: "fractal-ui-loader__stop-start", offset: "0" }),
|
|
1110
|
+
/* @__PURE__ */ jsx15("stop", { className: "fractal-ui-loader__stop-end", offset: "1" })
|
|
1111
|
+
] }),
|
|
1112
|
+
/* @__PURE__ */ jsxs13("linearGradient", { id: `${gradientId}-shine`, x1: "0", x2: "1", y1: "0", y2: "0", children: [
|
|
1113
|
+
/* @__PURE__ */ jsx15("stop", { offset: "0.4", stopColor: "white", stopOpacity: "0" }),
|
|
1114
|
+
/* @__PURE__ */ jsx15("stop", { offset: "0.5", stopColor: "white", stopOpacity: "0.62" }),
|
|
1115
|
+
/* @__PURE__ */ jsx15("stop", { offset: "0.6", stopColor: "white", stopOpacity: "0" })
|
|
1116
|
+
] }),
|
|
1117
|
+
/* @__PURE__ */ jsxs13("clipPath", { id: clipId, children: [
|
|
1118
|
+
/* @__PURE__ */ jsx15("path", { d: LEFT }),
|
|
1119
|
+
/* @__PURE__ */ jsx15("path", { d: CENTER }),
|
|
1120
|
+
/* @__PURE__ */ jsx15("path", { d: RIGHT })
|
|
1121
|
+
] })
|
|
1122
|
+
] }),
|
|
1123
|
+
/* @__PURE__ */ jsx15("path", { d: CENTER, fill: `url(#${gradientId})` }),
|
|
1124
|
+
/* @__PURE__ */ jsx15("path", { d: RIGHT, fill: `url(#${gradientId})` }),
|
|
1125
|
+
/* @__PURE__ */ jsx15("path", { d: LEFT, fill: `url(#${gradientId})` }),
|
|
1126
|
+
/* @__PURE__ */ jsx15("g", { clipPath: `url(#${clipId})`, children: /* @__PURE__ */ jsx15("g", { className: "fractal-ui-loader__shine-axis", transform: "translate(72 46) rotate(68.4)", children: /* @__PURE__ */ jsx15("rect", { className: "fractal-ui-loader__shine", x: "-160", y: "-100", width: "320", height: "200", fill: `url(#${gradientId}-shine)` }) }) })
|
|
1127
|
+
] })
|
|
1128
|
+
}
|
|
1129
|
+
);
|
|
1130
|
+
}
|
|
1131
|
+
|
|
437
1132
|
// src/components/Modal/Modal.tsx
|
|
438
|
-
import { jsx as
|
|
439
|
-
var CloseIcon = () => /* @__PURE__ */
|
|
440
|
-
function Modal({ open, onClose, title, children, danger, warn, footer, noClose, size = "sm", className }) {
|
|
441
|
-
|
|
1133
|
+
import { jsx as jsx16, jsxs as jsxs14 } from "react/jsx-runtime";
|
|
1134
|
+
var CloseIcon = () => /* @__PURE__ */ jsx16("svg", { width: "16", height: "16", viewBox: "0 0 16 16", fill: "none", xmlns: "http://www.w3.org/2000/svg", children: /* @__PURE__ */ jsx16("path", { d: "M12 4L4 12M4 4L12 12", stroke: "currentColor", strokeWidth: "1.5", strokeLinecap: "round", strokeLinejoin: "round" }) });
|
|
1135
|
+
function Modal({ open, onClose, title, children, danger, warn, footer, noClose, closeDisabled = false, size = "sm", loading = false, loadingLabel = "Loading", scrollable = false, className }) {
|
|
1136
|
+
const [bodyScrolled, setBodyScrolled] = React10.useState(false);
|
|
1137
|
+
useEscapeDismiss(80, onClose, open && !noClose && !closeDisabled);
|
|
1138
|
+
React10.useEffect(() => {
|
|
1139
|
+
if (open) setBodyScrolled(false);
|
|
1140
|
+
}, [open]);
|
|
442
1141
|
if (!open) return null;
|
|
443
1142
|
const sizeClass = `fractal-modal-panel--${size}`;
|
|
444
1143
|
const accentClass = danger ? "fractal-modal-panel--danger" : warn ? "fractal-modal-panel--warn" : "";
|
|
445
|
-
return
|
|
446
|
-
/* @__PURE__ */
|
|
1144
|
+
return createPortal2(
|
|
1145
|
+
/* @__PURE__ */ jsx16("div", { className: "fractal-modal-overlay", onClick: noClose || closeDisabled ? void 0 : onClose, children: /* @__PURE__ */ jsxs14(
|
|
447
1146
|
"div",
|
|
448
1147
|
{
|
|
449
|
-
className: cn("fractal-modal-panel", sizeClass, accentClass, className),
|
|
1148
|
+
className: cn("fractal-modal-panel", sizeClass, accentClass, scrollable && "fractal-modal-panel--scrollable", className),
|
|
450
1149
|
onClick: (e) => e.stopPropagation(),
|
|
451
1150
|
children: [
|
|
452
|
-
/* @__PURE__ */
|
|
453
|
-
|
|
454
|
-
|
|
455
|
-
|
|
456
|
-
|
|
457
|
-
|
|
1151
|
+
/* @__PURE__ */ jsxs14(
|
|
1152
|
+
"div",
|
|
1153
|
+
{
|
|
1154
|
+
className: cn(
|
|
1155
|
+
"fractal-modal-title-row",
|
|
1156
|
+
scrollable && "fractal-modal-title-row--scrollable",
|
|
1157
|
+
scrollable && bodyScrolled && "fractal-modal-title-row--scrolled"
|
|
1158
|
+
),
|
|
1159
|
+
children: [
|
|
1160
|
+
/* @__PURE__ */ jsx16("h3", { className: cn("fractal-modal-title", danger && "fractal-modal-title--danger", warn && "fractal-modal-title--warn"), children: title }),
|
|
1161
|
+
!noClose && /* @__PURE__ */ jsx16("button", { type: "button", onClick: onClose, title: "Close", disabled: closeDisabled, className: "fractal-modal-close", children: /* @__PURE__ */ jsx16(CloseIcon, {}) })
|
|
1162
|
+
]
|
|
1163
|
+
}
|
|
1164
|
+
),
|
|
1165
|
+
/* @__PURE__ */ jsx16(
|
|
1166
|
+
"div",
|
|
1167
|
+
{
|
|
1168
|
+
"aria-busy": loading || void 0,
|
|
1169
|
+
className: cn(
|
|
1170
|
+
"fractal-modal-body",
|
|
1171
|
+
size === "lg" && "fractal-modal-body--lg",
|
|
1172
|
+
loading && "fractal-modal-body--loading",
|
|
1173
|
+
scrollable && "fractal-modal-body--scrollable"
|
|
1174
|
+
),
|
|
1175
|
+
onScroll: scrollable ? (event) => setBodyScrolled(event.currentTarget.scrollTop > 0) : void 0,
|
|
1176
|
+
children: loading ? /* @__PURE__ */ jsx16(UILoader, { label: loadingLabel }) : children
|
|
1177
|
+
}
|
|
1178
|
+
),
|
|
1179
|
+
footer && /* @__PURE__ */ jsx16("div", { className: cn("fractal-modal-footer", scrollable && "fractal-modal-footer--divided"), children: footer })
|
|
458
1180
|
]
|
|
459
1181
|
}
|
|
460
1182
|
) }),
|
|
@@ -462,94 +1184,461 @@ function Modal({ open, onClose, title, children, danger, warn, footer, noClose,
|
|
|
462
1184
|
);
|
|
463
1185
|
}
|
|
464
1186
|
|
|
1187
|
+
// src/components/TableLayout/TableOverflowMenu.tsx
|
|
1188
|
+
import { useId as useId3, useLayoutEffect, useRef as useRef5, useState as useState5 } from "react";
|
|
1189
|
+
import { createPortal as createPortal3 } from "react-dom";
|
|
1190
|
+
import { Ellipsis } from "@mirror-physics/fractal-icons";
|
|
1191
|
+
import { jsx as jsx17, jsxs as jsxs15 } from "react/jsx-runtime";
|
|
1192
|
+
function TableOverflowMenu({ items, label, disabled, onSelect }) {
|
|
1193
|
+
const id = useId3();
|
|
1194
|
+
const trigger = useRef5(null);
|
|
1195
|
+
const panel = useRef5(null);
|
|
1196
|
+
const initialLast = useRef5(false);
|
|
1197
|
+
const [open, setOpen] = useState5(false);
|
|
1198
|
+
const [position, setPosition] = useState5({ top: 0, left: 0 });
|
|
1199
|
+
const buttons = () => [...panel.current?.querySelectorAll("button:not(:disabled)") ?? []];
|
|
1200
|
+
const close = (restore = true) => {
|
|
1201
|
+
setOpen(false);
|
|
1202
|
+
if (restore) trigger.current?.focus({ preventScroll: true });
|
|
1203
|
+
};
|
|
1204
|
+
useEscapeDismiss(100, () => close(), open);
|
|
1205
|
+
useLayoutEffect(() => {
|
|
1206
|
+
if (!open || !trigger.current || !panel.current) return;
|
|
1207
|
+
const place = () => {
|
|
1208
|
+
const anchor = trigger.current.getBoundingClientRect();
|
|
1209
|
+
const menu = panel.current.getBoundingClientRect();
|
|
1210
|
+
const above = window.innerHeight - anchor.bottom < menu.height + 8 && anchor.top > window.innerHeight - anchor.bottom;
|
|
1211
|
+
setPosition({
|
|
1212
|
+
top: Math.max(8, Math.min(above ? anchor.top - menu.height - 4 : anchor.bottom + 4, window.innerHeight - menu.height - 8)),
|
|
1213
|
+
left: Math.max(8, Math.min(anchor.right - menu.width, window.innerWidth - menu.width - 8))
|
|
1214
|
+
});
|
|
1215
|
+
};
|
|
1216
|
+
place();
|
|
1217
|
+
const enabled = buttons();
|
|
1218
|
+
(initialLast.current ? enabled[enabled.length - 1] : enabled[0])?.focus({ preventScroll: true });
|
|
1219
|
+
if (enabled.length === 0) panel.current.focus({ preventScroll: true });
|
|
1220
|
+
const outside = (event) => {
|
|
1221
|
+
if (!panel.current?.contains(event.target) && !trigger.current?.contains(event.target)) setOpen(false);
|
|
1222
|
+
};
|
|
1223
|
+
const scroll = (event) => {
|
|
1224
|
+
if (!panel.current?.contains(event.target)) setOpen(false);
|
|
1225
|
+
};
|
|
1226
|
+
const observer = new ResizeObserver(place);
|
|
1227
|
+
observer.observe(panel.current);
|
|
1228
|
+
document.addEventListener("pointerdown", outside);
|
|
1229
|
+
window.addEventListener("scroll", scroll, true);
|
|
1230
|
+
window.addEventListener("resize", place);
|
|
1231
|
+
return () => {
|
|
1232
|
+
observer.disconnect();
|
|
1233
|
+
document.removeEventListener("pointerdown", outside);
|
|
1234
|
+
window.removeEventListener("scroll", scroll, true);
|
|
1235
|
+
window.removeEventListener("resize", place);
|
|
1236
|
+
};
|
|
1237
|
+
}, [open]);
|
|
1238
|
+
useLayoutEffect(() => {
|
|
1239
|
+
if (disabled || items.length === 0) setOpen(false);
|
|
1240
|
+
}, [disabled, items.length]);
|
|
1241
|
+
if (items.length === 0) return null;
|
|
1242
|
+
return /* @__PURE__ */ jsxs15("div", { className: "fractal-table-overflow-trigger", children: [
|
|
1243
|
+
/* @__PURE__ */ jsx17(
|
|
1244
|
+
Button,
|
|
1245
|
+
{
|
|
1246
|
+
ref: trigger,
|
|
1247
|
+
buttonType: "ghost",
|
|
1248
|
+
controlSize: "sm",
|
|
1249
|
+
hasIconOnly: true,
|
|
1250
|
+
icon: /* @__PURE__ */ jsx17(Ellipsis, { "aria-hidden": true }),
|
|
1251
|
+
"aria-label": label,
|
|
1252
|
+
"aria-haspopup": "menu",
|
|
1253
|
+
"aria-expanded": open,
|
|
1254
|
+
"aria-controls": open ? id : void 0,
|
|
1255
|
+
disabled,
|
|
1256
|
+
onClick: () => {
|
|
1257
|
+
initialLast.current = false;
|
|
1258
|
+
setOpen(!open);
|
|
1259
|
+
},
|
|
1260
|
+
onKeyDown: (event) => {
|
|
1261
|
+
if (event.key === "ArrowDown" || event.key === "ArrowUp") {
|
|
1262
|
+
event.preventDefault();
|
|
1263
|
+
initialLast.current = event.key === "ArrowUp";
|
|
1264
|
+
setOpen(true);
|
|
1265
|
+
}
|
|
1266
|
+
}
|
|
1267
|
+
}
|
|
1268
|
+
),
|
|
1269
|
+
open && createPortal3(/* @__PURE__ */ jsx17(
|
|
1270
|
+
"div",
|
|
1271
|
+
{
|
|
1272
|
+
ref: panel,
|
|
1273
|
+
id,
|
|
1274
|
+
role: "menu",
|
|
1275
|
+
tabIndex: -1,
|
|
1276
|
+
"aria-label": label,
|
|
1277
|
+
className: "fractal-table-overflow-menu",
|
|
1278
|
+
style: position,
|
|
1279
|
+
onClick: (event) => event.stopPropagation(),
|
|
1280
|
+
onKeyDown: (event) => {
|
|
1281
|
+
event.stopPropagation();
|
|
1282
|
+
const enabled = buttons(), index = enabled.indexOf(document.activeElement);
|
|
1283
|
+
if (event.key === "Escape") {
|
|
1284
|
+
event.preventDefault();
|
|
1285
|
+
close();
|
|
1286
|
+
} else if (event.key === "Tab") {
|
|
1287
|
+
close();
|
|
1288
|
+
} else if (["ArrowDown", "ArrowUp", "Home", "End"].includes(event.key)) {
|
|
1289
|
+
event.preventDefault();
|
|
1290
|
+
const next = event.key === "Home" ? 0 : event.key === "End" ? enabled.length - 1 : (index + (event.key === "ArrowDown" ? 1 : -1) + enabled.length) % enabled.length;
|
|
1291
|
+
enabled[next]?.focus();
|
|
1292
|
+
} else if (event.key.length === 1 && /\S/.test(event.key)) {
|
|
1293
|
+
const ordered = [...enabled.slice(index + 1), ...enabled.slice(0, index + 1)];
|
|
1294
|
+
ordered.find((button) => button.textContent?.trim().toLocaleLowerCase().startsWith(event.key.toLocaleLowerCase()))?.focus();
|
|
1295
|
+
}
|
|
1296
|
+
},
|
|
1297
|
+
children: items.map((item) => /* @__PURE__ */ jsxs15(
|
|
1298
|
+
"button",
|
|
1299
|
+
{
|
|
1300
|
+
type: "button",
|
|
1301
|
+
role: "menuitem",
|
|
1302
|
+
tabIndex: -1,
|
|
1303
|
+
disabled: item.disabled,
|
|
1304
|
+
onClick: () => {
|
|
1305
|
+
onSelect(item.value);
|
|
1306
|
+
close();
|
|
1307
|
+
},
|
|
1308
|
+
children: [
|
|
1309
|
+
item.icon && /* @__PURE__ */ jsx17("span", { "aria-hidden": "true", children: item.icon }),
|
|
1310
|
+
item.label
|
|
1311
|
+
]
|
|
1312
|
+
},
|
|
1313
|
+
item.value
|
|
1314
|
+
))
|
|
1315
|
+
}
|
|
1316
|
+
), document.body)
|
|
1317
|
+
] });
|
|
1318
|
+
}
|
|
1319
|
+
|
|
1320
|
+
// src/components/TableLayout/TableLayout.tsx
|
|
1321
|
+
import { useLayoutEffect as useLayoutEffect2, useRef as useRef6, useState as useState6 } from "react";
|
|
1322
|
+
import { jsx as jsx18 } from "react/jsx-runtime";
|
|
1323
|
+
var length = (value) => typeof value === "number" ? `${value}px` : value;
|
|
1324
|
+
function columnStyle(column) {
|
|
1325
|
+
return {
|
|
1326
|
+
width: column.width,
|
|
1327
|
+
"--table-column-width": !column.width || column.width.includes("%") ? void 0 : `calc(${column.width} - 1px)`,
|
|
1328
|
+
"--table-column-min": length(column.minWidth),
|
|
1329
|
+
"--table-column-max": length(column.maxWidth)
|
|
1330
|
+
};
|
|
1331
|
+
}
|
|
1332
|
+
function useOverflow() {
|
|
1333
|
+
const ref = useRef6(null);
|
|
1334
|
+
const [overflow, setOverflow] = useState6(false);
|
|
1335
|
+
useLayoutEffect2(() => {
|
|
1336
|
+
const el = ref.current;
|
|
1337
|
+
if (!el) return;
|
|
1338
|
+
const measure = () => setOverflow(el.scrollWidth > el.clientWidth + 1 || el.scrollHeight > el.clientHeight + 1);
|
|
1339
|
+
const resize = new ResizeObserver(measure);
|
|
1340
|
+
const observe = () => {
|
|
1341
|
+
resize.disconnect();
|
|
1342
|
+
resize.observe(el);
|
|
1343
|
+
for (const child of el.children) resize.observe(child);
|
|
1344
|
+
measure();
|
|
1345
|
+
};
|
|
1346
|
+
const mutation = new MutationObserver(observe);
|
|
1347
|
+
mutation.observe(el, { childList: true, subtree: true, characterData: true });
|
|
1348
|
+
observe();
|
|
1349
|
+
return () => {
|
|
1350
|
+
resize.disconnect();
|
|
1351
|
+
mutation.disconnect();
|
|
1352
|
+
};
|
|
1353
|
+
}, []);
|
|
1354
|
+
return { ref, overflow };
|
|
1355
|
+
}
|
|
1356
|
+
function TableViewport({ children, maxHeight, label }) {
|
|
1357
|
+
const { ref, overflow } = useOverflow();
|
|
1358
|
+
return /* @__PURE__ */ jsx18("div", { ref, className: "fractal-table-viewport", style: { maxHeight }, tabIndex: overflow ? 0 : void 0, role: overflow ? "region" : void 0, "aria-label": overflow ? `${label}, scrollable table` : void 0, children });
|
|
1359
|
+
}
|
|
1360
|
+
function TableCellContent({ children, label }) {
|
|
1361
|
+
const { ref, overflow } = useOverflow();
|
|
1362
|
+
useLayoutEffect2(() => {
|
|
1363
|
+
const cell = ref.current;
|
|
1364
|
+
if (!cell) return;
|
|
1365
|
+
const wheel = (event) => {
|
|
1366
|
+
if (event.defaultPrevented || event.ctrlKey || !event.cancelable || Math.abs(event.deltaX) <= Math.abs(event.deltaY)) return;
|
|
1367
|
+
const range = cell.scrollWidth - cell.clientWidth;
|
|
1368
|
+
if (range <= 1) return;
|
|
1369
|
+
const rtl = getComputedStyle(cell).direction === "rtl";
|
|
1370
|
+
const left = rtl ? -range : 0, right = rtl ? 0 : range;
|
|
1371
|
+
if (event.deltaX > 0 ? cell.scrollLeft < right - 1 : cell.scrollLeft > left + 1) return;
|
|
1372
|
+
const table = cell.closest(".fractal-table-viewport");
|
|
1373
|
+
if (!table) return;
|
|
1374
|
+
const tableRange = table.scrollWidth - table.clientWidth;
|
|
1375
|
+
const tableRtl = getComputedStyle(table).direction === "rtl";
|
|
1376
|
+
const tableLeft = tableRtl ? -tableRange : 0, tableRight = tableRtl ? 0 : tableRange;
|
|
1377
|
+
if (event.deltaX > 0 ? table.scrollLeft >= tableRight - 1 : table.scrollLeft <= tableLeft + 1) return;
|
|
1378
|
+
const unit = event.deltaMode === 1 ? parseFloat(getComputedStyle(cell).lineHeight) || 16 : event.deltaMode === 2 ? table.clientWidth : 1;
|
|
1379
|
+
event.preventDefault();
|
|
1380
|
+
table.scrollLeft += event.deltaX * unit;
|
|
1381
|
+
};
|
|
1382
|
+
cell.addEventListener("wheel", wheel, { passive: false });
|
|
1383
|
+
return () => cell.removeEventListener("wheel", wheel);
|
|
1384
|
+
}, [ref]);
|
|
1385
|
+
return /* @__PURE__ */ jsx18(
|
|
1386
|
+
"div",
|
|
1387
|
+
{
|
|
1388
|
+
ref,
|
|
1389
|
+
className: "fractal-table-cell-scroll",
|
|
1390
|
+
"data-overflow": overflow || void 0,
|
|
1391
|
+
tabIndex: overflow ? 0 : void 0,
|
|
1392
|
+
role: overflow ? "region" : void 0,
|
|
1393
|
+
"aria-label": overflow ? `${label}, scroll horizontally for full content` : void 0,
|
|
1394
|
+
onKeyDown: (event) => {
|
|
1395
|
+
if (!overflow || event.target !== event.currentTarget) return;
|
|
1396
|
+
if (["ArrowLeft", "ArrowRight", "Home", "End"].includes(event.key)) {
|
|
1397
|
+
event.preventDefault();
|
|
1398
|
+
event.stopPropagation();
|
|
1399
|
+
const el = event.currentTarget;
|
|
1400
|
+
if (event.key === "ArrowLeft" || event.key === "ArrowRight") el.scrollBy({ left: event.key === "ArrowLeft" ? -40 : 40 });
|
|
1401
|
+
else el.scrollLeft = event.key === "Home" ? 0 : el.scrollWidth * (getComputedStyle(el).direction === "rtl" ? -1 : 1);
|
|
1402
|
+
} else if (event.key === " " || event.key === "Enter") event.stopPropagation();
|
|
1403
|
+
},
|
|
1404
|
+
children: /* @__PURE__ */ jsx18("div", { className: "fractal-table-cell-content", children })
|
|
1405
|
+
}
|
|
1406
|
+
);
|
|
1407
|
+
}
|
|
1408
|
+
|
|
465
1409
|
// src/components/DataTable/DataTable.tsx
|
|
466
|
-
import { jsx as
|
|
467
|
-
function DataTable({ columns, data, emptyMessage, header, size = "md", className }) {
|
|
468
|
-
return /* @__PURE__ */
|
|
469
|
-
header && /* @__PURE__ */
|
|
470
|
-
data.length === 0 ? /* @__PURE__ */
|
|
471
|
-
/* @__PURE__ */
|
|
472
|
-
|
|
1410
|
+
import { jsx as jsx19, jsxs as jsxs16 } from "react/jsx-runtime";
|
|
1411
|
+
function DataTable({ columns, data, emptyMessage, header, size = "md", className, overflowMenu, layout = "fill", stickyHeader = false, stickyFirstColumn = false, maxHeight, "aria-label": ariaLabel = "Data table" }) {
|
|
1412
|
+
return /* @__PURE__ */ jsx19("div", { className: cn("fractal-table-layout", "fractal-datatable", `fractal-datatable--${size}`, className), "data-overflow-menu": Boolean(overflowMenu), "data-table-layout": layout, "data-sticky-first": stickyFirstColumn, "data-sticky-header": stickyHeader, children: /* @__PURE__ */ jsxs16("div", { className: "fractal-datatable-surface", children: [
|
|
1413
|
+
header && /* @__PURE__ */ jsx19("div", { className: "fractal-datatable-header", children: header }),
|
|
1414
|
+
data.length === 0 ? /* @__PURE__ */ jsx19("div", { className: "fractal-datatable-empty", children: emptyMessage || "No data" }) : /* @__PURE__ */ jsx19(TableViewport, { maxHeight, label: ariaLabel, children: /* @__PURE__ */ jsxs16("table", { "aria-label": ariaLabel, className: "fractal-datatable-table", children: [
|
|
1415
|
+
/* @__PURE__ */ jsx19("thead", { children: /* @__PURE__ */ jsxs16("tr", { className: "fractal-datatable-thead-row", children: [
|
|
1416
|
+
columns.map((col, columnIndex) => /* @__PURE__ */ jsx19("th", { scope: "col", className: "fractal-datatable-th", style: columnStyle(col), "data-pinned-column": columnIndex === 0 ? "data" : void 0, children: /* @__PURE__ */ jsx19(TableCellContent, { label: `${col.header} column`, children: col.header }) }, col.key)),
|
|
1417
|
+
overflowMenu && /* @__PURE__ */ jsx19("th", { scope: "col", "aria-label": "Row actions", className: "fractal-datatable-th fractal-table-overflow-cell", "data-pinned-column": "overflow" })
|
|
1418
|
+
] }) }),
|
|
1419
|
+
/* @__PURE__ */ jsx19("tbody", { children: data.map((row, rowIndex) => /* @__PURE__ */ jsxs16(
|
|
473
1420
|
"tr",
|
|
474
1421
|
{
|
|
475
1422
|
className: "fractal-datatable-row",
|
|
476
|
-
children:
|
|
1423
|
+
children: [
|
|
1424
|
+
columns.map((col, columnIndex) => /* @__PURE__ */ jsx19("td", { className: "fractal-datatable-td", style: columnStyle(col), "data-pinned-column": columnIndex === 0 ? "data" : void 0, children: /* @__PURE__ */ jsx19(TableCellContent, { label: `${col.header || "Value"}, row ${rowIndex + 1}`, children: col.render(row, rowIndex) }) }, col.key)),
|
|
1425
|
+
overflowMenu && /* @__PURE__ */ jsx19("td", { className: "fractal-datatable-td fractal-table-overflow-cell", "data-pinned-column": "overflow", children: /* @__PURE__ */ jsx19(TableOverflowMenu, { items: overflowMenu.items(row, rowIndex), label: overflowMenu.getLabel?.(row, rowIndex) ?? `Actions for row ${rowIndex + 1}`, disabled: overflowMenu.isDisabled?.(row, rowIndex), onSelect: (value) => overflowMenu.onSelect(value, row, rowIndex) }) })
|
|
1426
|
+
]
|
|
477
1427
|
},
|
|
478
1428
|
rowIndex
|
|
479
1429
|
)) })
|
|
480
|
-
] })
|
|
1430
|
+
] }) })
|
|
481
1431
|
] }) });
|
|
482
1432
|
}
|
|
483
1433
|
|
|
484
1434
|
// src/components/Dropdown/Dropdown.tsx
|
|
485
|
-
import * as
|
|
486
|
-
import { ChevronDown, ChevronUp } from "@mirror-physics/fractal-icons";
|
|
487
|
-
|
|
488
|
-
|
|
1435
|
+
import * as React11 from "react";
|
|
1436
|
+
import { Close as Close2, Check as Check2, MagnifyingGlass as MagnifyingGlass2, ChevronDown, ChevronLeft, ChevronRight as ChevronRight2, ChevronUp } from "@mirror-physics/fractal-icons";
|
|
1437
|
+
|
|
1438
|
+
// src/components/Dropdown/position.ts
|
|
1439
|
+
function isDropdownTriggerVisible(trigger, bounds) {
|
|
1440
|
+
return trigger.right > bounds.left && trigger.left < bounds.right && trigger.bottom > bounds.top && trigger.top < bounds.bottom;
|
|
1441
|
+
}
|
|
1442
|
+
function positionDropdown(trigger, panel, bounds, direction, align) {
|
|
1443
|
+
const gap = 4;
|
|
1444
|
+
const width = Math.min(panel.width, Math.max(0, bounds.right - bounds.left));
|
|
1445
|
+
let maxHeight = Math.max(0, bounds.bottom - bounds.top);
|
|
1446
|
+
let left;
|
|
1447
|
+
let top;
|
|
1448
|
+
if (direction === "left" || direction === "right") {
|
|
1449
|
+
const after = bounds.right - trigger.right - gap;
|
|
1450
|
+
const before = trigger.left - bounds.left - gap;
|
|
1451
|
+
let placeRight = direction === "right";
|
|
1452
|
+
if (width > (placeRight ? after : before) && (placeRight ? before > after : after > before)) {
|
|
1453
|
+
placeRight = !placeRight;
|
|
1454
|
+
}
|
|
1455
|
+
left = placeRight ? trigger.right + gap : trigger.left - width - gap;
|
|
1456
|
+
top = trigger.top;
|
|
1457
|
+
} else {
|
|
1458
|
+
const below = Math.max(0, bounds.bottom - trigger.bottom - gap);
|
|
1459
|
+
const above = Math.max(0, trigger.top - bounds.top - gap);
|
|
1460
|
+
let placeAbove = direction === "up";
|
|
1461
|
+
if (panel.height > (placeAbove ? above : below) && (placeAbove ? below > above : above > below)) {
|
|
1462
|
+
placeAbove = !placeAbove;
|
|
1463
|
+
}
|
|
1464
|
+
maxHeight = Math.min(maxHeight, placeAbove ? above : below);
|
|
1465
|
+
top = placeAbove ? trigger.top - Math.min(panel.height, maxHeight) - gap : trigger.bottom + gap;
|
|
1466
|
+
left = align === "right" ? trigger.right - width : trigger.left;
|
|
1467
|
+
}
|
|
1468
|
+
const height = Math.min(panel.height, maxHeight);
|
|
1469
|
+
return {
|
|
1470
|
+
left: Math.max(bounds.left, Math.min(left, bounds.right - width)),
|
|
1471
|
+
top: Math.max(bounds.top, Math.min(top, bounds.bottom - height)),
|
|
1472
|
+
maxHeight
|
|
1473
|
+
};
|
|
1474
|
+
}
|
|
1475
|
+
|
|
1476
|
+
// src/components/Dropdown/Dropdown.tsx
|
|
1477
|
+
import { Fragment as Fragment2, jsx as jsx20, jsxs as jsxs17 } from "react/jsx-runtime";
|
|
489
1478
|
function Dropdown({
|
|
490
1479
|
items,
|
|
491
|
-
selectedValue,
|
|
1480
|
+
selectedValue = "",
|
|
492
1481
|
onSelect,
|
|
493
|
-
|
|
1482
|
+
multiple = false,
|
|
1483
|
+
selectedValues = [],
|
|
1484
|
+
onSelectionChange,
|
|
1485
|
+
searchable = false,
|
|
1486
|
+
searchPlaceholder = "Find an option",
|
|
1487
|
+
emptyMessage = "No matching options.",
|
|
1488
|
+
triggerLabel,
|
|
1489
|
+
fieldLabel,
|
|
1490
|
+
clearable = Boolean(fieldLabel),
|
|
494
1491
|
direction = "down",
|
|
495
1492
|
align = "left",
|
|
1493
|
+
maxHeight = 320,
|
|
1494
|
+
collisionPadding = 8,
|
|
1495
|
+
triggerOrientation = "horizontal",
|
|
496
1496
|
triggerContent,
|
|
497
1497
|
label,
|
|
1498
|
+
iconOnly = false,
|
|
498
1499
|
noChevron = false,
|
|
499
|
-
size = "
|
|
1500
|
+
size: sizeAlias = "lg",
|
|
1501
|
+
controlSize,
|
|
1502
|
+
triggerId,
|
|
500
1503
|
triggerVariant = "outline",
|
|
501
1504
|
className,
|
|
502
1505
|
triggerClassName,
|
|
503
1506
|
panelClassName,
|
|
504
|
-
closeOnSelect = true
|
|
1507
|
+
closeOnSelect = true,
|
|
1508
|
+
disabled = false
|
|
505
1509
|
}) {
|
|
506
|
-
const [
|
|
507
|
-
const
|
|
508
|
-
const
|
|
509
|
-
const
|
|
510
|
-
const
|
|
1510
|
+
const [query, setQuery] = React11.useState("");
|
|
1511
|
+
const searchRef = React11.useRef(null);
|
|
1512
|
+
const searchContainerRef = React11.useRef(null);
|
|
1513
|
+
const optionsRef = React11.useRef(null);
|
|
1514
|
+
const [optionsScrolled, setOptionsScrolled] = React11.useState(false);
|
|
1515
|
+
const accessibleLabel = triggerLabel ?? fieldLabel ?? "Options";
|
|
1516
|
+
const size = controlSize ?? sizeAlias;
|
|
1517
|
+
const canClear = clearable && !disabled && (multiple ? selectedValues.length > 0 && Boolean(onSelectionChange) : Boolean(selectedValue) && Boolean(onSelect));
|
|
1518
|
+
const [open, setOpen] = React11.useState(false);
|
|
1519
|
+
React11.useEffect(() => {
|
|
1520
|
+
if (!open) setQuery("");
|
|
1521
|
+
}, [open]);
|
|
1522
|
+
const rootRef = React11.useRef(null);
|
|
1523
|
+
const menuId = React11.useId();
|
|
1524
|
+
const focusOnOpen = React11.useRef(false);
|
|
1525
|
+
const triggerRef = React11.useRef(null);
|
|
1526
|
+
const panelRef = React11.useRef(null);
|
|
1527
|
+
const [panelStyle, setPanelStyle] = React11.useState({});
|
|
1528
|
+
const renderableItems = items.filter(
|
|
511
1529
|
(item) => item.icon != null || item.description != null && (typeof item.description === "string" ? item.description !== "" : true)
|
|
512
1530
|
);
|
|
513
|
-
|
|
514
|
-
|
|
515
|
-
const
|
|
516
|
-
|
|
517
|
-
|
|
518
|
-
|
|
519
|
-
if (!open || !triggerRef.current || !panelRef.current) return;
|
|
520
|
-
const triggerRect = triggerRef.current.getBoundingClientRect();
|
|
521
|
-
const panelRect = panelRef.current.getBoundingClientRect();
|
|
522
|
-
const vw = window.innerWidth;
|
|
523
|
-
const vh = window.innerHeight;
|
|
524
|
-
const spaceBelow = vh - triggerRect.bottom - MARGIN;
|
|
525
|
-
const spaceAbove = triggerRect.top - MARGIN;
|
|
526
|
-
let placeAbove = isUp;
|
|
527
|
-
if (placeAbove && panelRect.height > spaceAbove && spaceBelow > spaceAbove) {
|
|
528
|
-
placeAbove = false;
|
|
529
|
-
} else if (!placeAbove && panelRect.height > spaceBelow && spaceAbove > spaceBelow) {
|
|
530
|
-
placeAbove = true;
|
|
1531
|
+
const normalizedQuery = query.trim().toLocaleLowerCase();
|
|
1532
|
+
let groupTitle = "";
|
|
1533
|
+
const matching = new Set(renderableItems.filter((item) => {
|
|
1534
|
+
if (item.kind === "header") {
|
|
1535
|
+
groupTitle = String(item.description ?? "");
|
|
1536
|
+
return false;
|
|
531
1537
|
}
|
|
532
|
-
|
|
533
|
-
|
|
534
|
-
|
|
535
|
-
if (
|
|
536
|
-
|
|
537
|
-
|
|
538
|
-
|
|
539
|
-
|
|
540
|
-
|
|
1538
|
+
return `${groupTitle} ${typeof item.description === "string" ? item.description : item.value}`.toLocaleLowerCase().includes(normalizedQuery);
|
|
1539
|
+
}).map((item) => item.value));
|
|
1540
|
+
const visibleItems = renderableItems.filter((item, index) => {
|
|
1541
|
+
if (item.kind !== "header") return matching.has(item.value);
|
|
1542
|
+
const nextHeader = renderableItems.findIndex((next, i) => i > index && next.kind === "header");
|
|
1543
|
+
return renderableItems.slice(index + 1, nextHeader < 0 ? void 0 : nextHeader).some((next) => matching.has(next.value));
|
|
1544
|
+
});
|
|
1545
|
+
const selectableItems = visibleItems.filter((i) => i.kind !== "header");
|
|
1546
|
+
const selected = items.find((i) => i.value === selectedValue && i.kind !== "header") ?? (fieldLabel && !selectedValue && !multiple ? void 0 : selectableItems[0] ?? visibleItems[0]);
|
|
1547
|
+
const ChevronIcon = direction === "up" ? ChevronUp : direction === "left" ? ChevronLeft : direction === "right" ? ChevronRight2 : ChevronDown;
|
|
1548
|
+
useEscapeDismiss(100, () => {
|
|
1549
|
+
setOpen(false);
|
|
1550
|
+
triggerRef.current?.focus();
|
|
1551
|
+
}, open);
|
|
1552
|
+
React11.useLayoutEffect(() => {
|
|
1553
|
+
if (!open) return;
|
|
1554
|
+
if (optionsRef.current) optionsRef.current.scrollTop = 0;
|
|
1555
|
+
setOptionsScrolled(false);
|
|
1556
|
+
}, [open, query]);
|
|
1557
|
+
React11.useLayoutEffect(() => {
|
|
1558
|
+
const root = rootRef.current;
|
|
1559
|
+
const trigger = triggerRef.current;
|
|
1560
|
+
const panel = panelRef.current;
|
|
1561
|
+
if (!open || !root || !trigger || !panel) return;
|
|
1562
|
+
const updatePosition = () => {
|
|
1563
|
+
const viewport = window.visualViewport;
|
|
1564
|
+
const bounds = {
|
|
1565
|
+
left: viewport?.offsetLeft ?? 0,
|
|
1566
|
+
top: viewport?.offsetTop ?? 0,
|
|
1567
|
+
right: (viewport?.offsetLeft ?? 0) + (viewport?.width ?? document.documentElement.clientWidth),
|
|
1568
|
+
bottom: (viewport?.offsetTop ?? 0) + (viewport?.height ?? document.documentElement.clientHeight)
|
|
1569
|
+
};
|
|
1570
|
+
for (let ancestor = root.parentElement; ancestor; ancestor = ancestor.parentElement) {
|
|
1571
|
+
const style = getComputedStyle(ancestor);
|
|
1572
|
+
const rect = ancestor.getBoundingClientRect();
|
|
1573
|
+
if (/(auto|scroll|hidden|clip)/.test(style.overflowX)) {
|
|
1574
|
+
bounds.left = Math.max(bounds.left, rect.left + ancestor.clientLeft);
|
|
1575
|
+
bounds.right = Math.min(bounds.right, rect.left + ancestor.clientLeft + ancestor.clientWidth);
|
|
1576
|
+
}
|
|
1577
|
+
if (/(auto|scroll|hidden|clip)/.test(style.overflowY)) {
|
|
1578
|
+
bounds.top = Math.max(bounds.top, rect.top + ancestor.clientTop);
|
|
1579
|
+
bounds.bottom = Math.min(bounds.bottom, rect.top + ancestor.clientTop + ancestor.clientHeight);
|
|
1580
|
+
}
|
|
541
1581
|
}
|
|
542
|
-
|
|
543
|
-
|
|
544
|
-
|
|
545
|
-
|
|
546
|
-
|
|
547
|
-
|
|
1582
|
+
const triggerRect = trigger.getBoundingClientRect();
|
|
1583
|
+
if (!isDropdownTriggerVisible(triggerRect, bounds)) {
|
|
1584
|
+
focusOnOpen.current = false;
|
|
1585
|
+
setOpen(false);
|
|
1586
|
+
return false;
|
|
1587
|
+
}
|
|
1588
|
+
const padding = Math.max(0, collisionPadding);
|
|
1589
|
+
bounds.left += padding;
|
|
1590
|
+
bounds.right = Math.max(bounds.left, bounds.right - padding);
|
|
1591
|
+
bounds.top += padding;
|
|
1592
|
+
bounds.bottom = Math.max(bounds.top, bounds.bottom - padding);
|
|
1593
|
+
const rootRect = root.getBoundingClientRect();
|
|
1594
|
+
const availableWidth = bounds.right - bounds.left;
|
|
1595
|
+
const heightLimit = Math.max(0, maxHeight);
|
|
1596
|
+
panel.style.maxWidth = `${availableWidth}px`;
|
|
1597
|
+
panel.style.minWidth = `${Math.min(triggerRect.width, availableWidth)}px`;
|
|
1598
|
+
const panelRect = panel.getBoundingClientRect();
|
|
1599
|
+
const desiredHeight = Math.min(heightLimit, (optionsRef.current?.scrollHeight ?? 0) + (searchContainerRef.current?.offsetHeight ?? 0) + parseFloat(getComputedStyle(panel).paddingTop) + parseFloat(getComputedStyle(panel).paddingBottom) + panel.offsetHeight - panel.clientHeight);
|
|
1600
|
+
const position = positionDropdown(triggerRect, { width: panelRect.width, height: desiredHeight }, bounds, direction, align);
|
|
1601
|
+
const nextStyle = {
|
|
1602
|
+
left: position.left - rootRect.left - root.clientLeft + root.scrollLeft,
|
|
1603
|
+
top: position.top - rootRect.top - root.clientTop + root.scrollTop,
|
|
1604
|
+
minWidth: Math.min(triggerRect.width, availableWidth),
|
|
1605
|
+
maxWidth: availableWidth,
|
|
1606
|
+
maxHeight: Math.min(heightLimit, position.maxHeight)
|
|
1607
|
+
};
|
|
1608
|
+
for (const key of Object.keys(nextStyle)) {
|
|
1609
|
+
panel.style[key] = `${nextStyle[key]}px`;
|
|
548
1610
|
}
|
|
1611
|
+
setPanelStyle((previous) => Object.entries(nextStyle).every(([key, value]) => previous[key] === value) ? previous : nextStyle);
|
|
1612
|
+
return true;
|
|
1613
|
+
};
|
|
1614
|
+
if (!updatePosition()) return;
|
|
1615
|
+
if (searchable && !panel.contains(document.activeElement)) searchRef.current?.focus({ preventScroll: true });
|
|
1616
|
+
if (focusOnOpen.current) {
|
|
1617
|
+
focusOnOpen.current = false;
|
|
1618
|
+
const option = panel.querySelector('[aria-selected="true"]') ?? panel.querySelector('[role="option"]');
|
|
1619
|
+
option?.focus({ preventScroll: true });
|
|
1620
|
+
option?.scrollIntoView({ block: "nearest" });
|
|
1621
|
+
}
|
|
1622
|
+
const resize = new ResizeObserver(updatePosition);
|
|
1623
|
+
resize.observe(root);
|
|
1624
|
+
resize.observe(panel);
|
|
1625
|
+
if (optionsRef.current) resize.observe(optionsRef.current);
|
|
1626
|
+
for (let ancestor = root.parentElement; ancestor; ancestor = ancestor.parentElement) {
|
|
1627
|
+
resize.observe(ancestor);
|
|
549
1628
|
}
|
|
550
|
-
|
|
551
|
-
|
|
552
|
-
|
|
1629
|
+
window.addEventListener("resize", updatePosition);
|
|
1630
|
+
window.addEventListener("scroll", updatePosition, true);
|
|
1631
|
+
window.visualViewport?.addEventListener("resize", updatePosition);
|
|
1632
|
+
window.visualViewport?.addEventListener("scroll", updatePosition);
|
|
1633
|
+
return () => {
|
|
1634
|
+
resize.disconnect();
|
|
1635
|
+
window.removeEventListener("resize", updatePosition);
|
|
1636
|
+
window.removeEventListener("scroll", updatePosition, true);
|
|
1637
|
+
window.visualViewport?.removeEventListener("resize", updatePosition);
|
|
1638
|
+
window.visualViewport?.removeEventListener("scroll", updatePosition);
|
|
1639
|
+
};
|
|
1640
|
+
}, [open, direction, align, maxHeight, collisionPadding, items, label, query, searchable]);
|
|
1641
|
+
React11.useEffect(() => {
|
|
553
1642
|
if (!open) return;
|
|
554
1643
|
const handleClickOutside = (e) => {
|
|
555
1644
|
const target = e.target;
|
|
@@ -559,75 +1648,128 @@ function Dropdown({
|
|
|
559
1648
|
document.addEventListener("mousedown", handleClickOutside);
|
|
560
1649
|
return () => document.removeEventListener("mousedown", handleClickOutside);
|
|
561
1650
|
}, [open]);
|
|
562
|
-
|
|
563
|
-
|
|
1651
|
+
if (renderableItems.length === 0) return null;
|
|
1652
|
+
return /* @__PURE__ */ jsxs17("div", { ref: rootRef, "data-control-size": size, "data-filled": multiple ? selectedValues.length > 0 : Boolean(selectedValue), "data-open": open, "data-clearable": canClear || void 0, className: cn("fractal-dropdown", fieldLabel && "fractal-floating-field fractal-floating-field--dropdown", className), children: [
|
|
1653
|
+
/* @__PURE__ */ jsxs17(
|
|
564
1654
|
"button",
|
|
565
1655
|
{
|
|
566
1656
|
ref: triggerRef,
|
|
1657
|
+
id: triggerId ?? `${menuId}-trigger`,
|
|
1658
|
+
"data-control-size": size,
|
|
567
1659
|
type: "button",
|
|
568
|
-
|
|
1660
|
+
disabled,
|
|
1661
|
+
"aria-haspopup": searchable ? "dialog" : "listbox",
|
|
569
1662
|
"aria-expanded": open,
|
|
570
|
-
"aria-
|
|
1663
|
+
"aria-controls": open ? searchable ? menuId : `${menuId}-options` : void 0,
|
|
1664
|
+
onKeyDown: (event) => {
|
|
1665
|
+
if (event.key === "ArrowDown" || event.key === "ArrowUp") {
|
|
1666
|
+
event.preventDefault();
|
|
1667
|
+
if (open) {
|
|
1668
|
+
const option = panelRef.current?.querySelector('[aria-selected="true"]') ?? panelRef.current?.querySelector('[role="option"]');
|
|
1669
|
+
option?.focus({ preventScroll: true });
|
|
1670
|
+
option?.scrollIntoView({ block: "nearest" });
|
|
1671
|
+
} else {
|
|
1672
|
+
focusOnOpen.current = true;
|
|
1673
|
+
setOpen(true);
|
|
1674
|
+
}
|
|
1675
|
+
}
|
|
1676
|
+
},
|
|
1677
|
+
"aria-label": accessibleLabel,
|
|
571
1678
|
onClick: () => setOpen((o) => !o),
|
|
572
1679
|
className: cn(
|
|
1680
|
+
"fractal-control",
|
|
573
1681
|
"fractal-dropdown-trigger",
|
|
574
1682
|
`fractal-dropdown-trigger--${size}`,
|
|
575
1683
|
`fractal-dropdown-trigger--${triggerVariant}`,
|
|
1684
|
+
`fractal-dropdown-trigger--${triggerOrientation}`,
|
|
1685
|
+
iconOnly && "fractal-dropdown-trigger--icon-only",
|
|
576
1686
|
triggerClassName
|
|
577
1687
|
),
|
|
578
1688
|
children: [
|
|
579
|
-
triggerContent != null ? triggerContent : /* @__PURE__ */
|
|
580
|
-
selected
|
|
581
|
-
selected
|
|
582
|
-
] }),
|
|
583
|
-
!noChevron && /* @__PURE__ */
|
|
1689
|
+
/* @__PURE__ */ jsx20("span", { className: fieldLabel ? "fractal-dropdown-field-value" : void 0, style: fieldLabel ? void 0 : { display: "contents" }, children: triggerContent != null ? triggerContent : /* @__PURE__ */ jsxs17(Fragment2, { children: [
|
|
1690
|
+
selected?.icon != null && /* @__PURE__ */ jsx20("span", { className: "fractal-dropdown-icon fractal-dropdown-icon--trigger", children: selected?.icon }),
|
|
1691
|
+
selected?.description != null && (typeof selected?.description !== "string" || selected?.description !== "") && /* @__PURE__ */ jsx20("span", { className: "fractal-dropdown-selected-text", children: selected?.description })
|
|
1692
|
+
] }) }),
|
|
1693
|
+
!noChevron && !iconOnly && /* @__PURE__ */ jsx20("span", { className: "fractal-dropdown-chevron", "aria-hidden": true, children: /* @__PURE__ */ jsx20(ChevronIcon, { size: size === "sm" ? 14 : 16 }) })
|
|
584
1694
|
]
|
|
585
1695
|
}
|
|
586
1696
|
),
|
|
587
|
-
|
|
1697
|
+
canClear && /* @__PURE__ */ jsx20("button", { type: "button", className: "fractal-dropdown-clear", "aria-label": `Clear ${accessibleLabel}`, onClick: () => {
|
|
1698
|
+
if (multiple) onSelectionChange?.([]);
|
|
1699
|
+
else onSelect?.("");
|
|
1700
|
+
setOpen(false);
|
|
1701
|
+
setQuery("");
|
|
1702
|
+
triggerRef.current?.focus();
|
|
1703
|
+
}, children: /* @__PURE__ */ jsx20(Close2, { "aria-hidden": "true" }) }),
|
|
1704
|
+
fieldLabel ? /* @__PURE__ */ jsx20(FloatingFieldBorder, { label: fieldLabel }) : null,
|
|
1705
|
+
fieldLabel ? /* @__PURE__ */ jsx20("label", { className: "fractal-floating-field__label", htmlFor: triggerId ?? `${menuId}-trigger`, children: fieldLabel }) : null,
|
|
1706
|
+
open && /* @__PURE__ */ jsxs17(
|
|
588
1707
|
"div",
|
|
589
1708
|
{
|
|
590
1709
|
ref: panelRef,
|
|
591
|
-
|
|
592
|
-
|
|
593
|
-
|
|
594
|
-
|
|
595
|
-
|
|
596
|
-
|
|
597
|
-
|
|
598
|
-
|
|
599
|
-
|
|
600
|
-
|
|
601
|
-
|
|
602
|
-
|
|
603
|
-
|
|
604
|
-
|
|
605
|
-
|
|
606
|
-
|
|
607
|
-
|
|
608
|
-
|
|
609
|
-
|
|
610
|
-
|
|
611
|
-
|
|
612
|
-
|
|
613
|
-
|
|
614
|
-
|
|
615
|
-
|
|
616
|
-
|
|
617
|
-
|
|
618
|
-
|
|
619
|
-
},
|
|
620
|
-
|
|
621
|
-
|
|
622
|
-
|
|
623
|
-
|
|
624
|
-
|
|
625
|
-
|
|
626
|
-
|
|
627
|
-
|
|
628
|
-
|
|
629
|
-
|
|
630
|
-
|
|
1710
|
+
id: menuId,
|
|
1711
|
+
onKeyDown: (event) => {
|
|
1712
|
+
if (event.target === searchRef.current && event.key !== "ArrowDown") return;
|
|
1713
|
+
if (!["ArrowDown", "ArrowUp", "Home", "End"].includes(event.key)) return;
|
|
1714
|
+
event.preventDefault();
|
|
1715
|
+
const options = Array.from(panelRef.current?.querySelectorAll('[role="option"]') ?? []);
|
|
1716
|
+
const current = options.indexOf(document.activeElement);
|
|
1717
|
+
const index = event.key === "Home" ? 0 : event.key === "End" ? options.length - 1 : (current + (event.key === "ArrowDown" ? 1 : -1) + options.length) % options.length;
|
|
1718
|
+
options[index]?.focus({ preventScroll: true });
|
|
1719
|
+
options[index]?.scrollIntoView({ block: "nearest" });
|
|
1720
|
+
},
|
|
1721
|
+
role: searchable ? "dialog" : void 0,
|
|
1722
|
+
"aria-label": accessibleLabel,
|
|
1723
|
+
className: cn("fractal-dropdown-panel", `fractal-dropdown-panel--${size}`, panelClassName),
|
|
1724
|
+
style: panelStyle,
|
|
1725
|
+
children: [
|
|
1726
|
+
searchable && /* @__PURE__ */ jsx20("div", { ref: searchContainerRef, className: "fractal-dropdown-search-container", "data-scrolled": optionsScrolled, children: /* @__PURE__ */ jsxs17("div", { className: "fractal-dropdown-search", children: [
|
|
1727
|
+
/* @__PURE__ */ jsx20(MagnifyingGlass2, { "aria-hidden": "true" }),
|
|
1728
|
+
/* @__PURE__ */ jsx20("input", { ref: searchRef, type: "search", "aria-label": searchPlaceholder, placeholder: searchPlaceholder, value: query, onChange: (event) => setQuery(event.target.value) })
|
|
1729
|
+
] }) }),
|
|
1730
|
+
/* @__PURE__ */ jsxs17("div", { ref: optionsRef, className: "fractal-dropdown-options", onScroll: (event) => setOptionsScrolled(event.currentTarget.scrollTop > 0), role: "listbox", id: `${menuId}-options`, "aria-label": accessibleLabel, "aria-multiselectable": multiple || void 0, children: [
|
|
1731
|
+
label != null && /* @__PURE__ */ jsx20("div", { className: "fractal-dropdown-label", children: label }),
|
|
1732
|
+
visibleItems.map((item, index) => {
|
|
1733
|
+
const topDivider = item.border === "top" ? /* @__PURE__ */ jsx20("div", { className: "fractal-dropdown-separator" }) : null;
|
|
1734
|
+
const bottomDivider = item.border === "bottom" ? /* @__PURE__ */ jsx20("div", { className: "fractal-dropdown-separator" }) : null;
|
|
1735
|
+
if (item.kind === "header") {
|
|
1736
|
+
return /* @__PURE__ */ jsxs17(React11.Fragment, { children: [
|
|
1737
|
+
topDivider,
|
|
1738
|
+
/* @__PURE__ */ jsx20("div", { role: "presentation", className: "fractal-dropdown-label", children: item.description }),
|
|
1739
|
+
bottomDivider
|
|
1740
|
+
] }, `header-${index}`);
|
|
1741
|
+
}
|
|
1742
|
+
const isSelected = multiple ? selectedValues.includes(item.value) : item.value === selectedValue;
|
|
1743
|
+
return /* @__PURE__ */ jsxs17(React11.Fragment, { children: [
|
|
1744
|
+
topDivider,
|
|
1745
|
+
/* @__PURE__ */ jsxs17(
|
|
1746
|
+
"button",
|
|
1747
|
+
{
|
|
1748
|
+
type: "button",
|
|
1749
|
+
role: "option",
|
|
1750
|
+
"aria-selected": isSelected,
|
|
1751
|
+
onClick: () => {
|
|
1752
|
+
if (multiple) onSelectionChange?.(isSelected ? selectedValues.filter((value) => value !== item.value) : [...selectedValues, item.value]);
|
|
1753
|
+
else onSelect?.(item.value);
|
|
1754
|
+
if (!multiple && closeOnSelect) {
|
|
1755
|
+
setOpen(false);
|
|
1756
|
+
triggerRef.current?.focus();
|
|
1757
|
+
}
|
|
1758
|
+
},
|
|
1759
|
+
className: "fractal-dropdown-option",
|
|
1760
|
+
children: [
|
|
1761
|
+
multiple && /* @__PURE__ */ jsx20("span", { className: "fractal-dropdown-checkbox", "data-checked": isSelected, "aria-hidden": "true", children: isSelected && /* @__PURE__ */ jsx20(Check2, {}) }),
|
|
1762
|
+
item.icon != null && /* @__PURE__ */ jsx20("span", { className: "fractal-dropdown-icon", children: item.icon }),
|
|
1763
|
+
item.description != null && (typeof item.description !== "string" || item.description !== "") && /* @__PURE__ */ jsx20("span", { className: "fractal-dropdown-option-text", children: item.description }),
|
|
1764
|
+
item.trailing != null && /* @__PURE__ */ jsx20("span", { className: "fractal-dropdown-trailing", children: item.trailing })
|
|
1765
|
+
]
|
|
1766
|
+
}
|
|
1767
|
+
),
|
|
1768
|
+
bottomDivider
|
|
1769
|
+
] }, item.value);
|
|
1770
|
+
}),
|
|
1771
|
+
!selectableItems.length && /* @__PURE__ */ jsx20("p", { role: "status", className: "fractal-dropdown-label", children: emptyMessage })
|
|
1772
|
+
] })
|
|
631
1773
|
]
|
|
632
1774
|
}
|
|
633
1775
|
)
|
|
@@ -635,10 +1777,10 @@ function Dropdown({
|
|
|
635
1777
|
}
|
|
636
1778
|
|
|
637
1779
|
// src/components/Link/Link.tsx
|
|
638
|
-
import * as
|
|
639
|
-
import { jsx as
|
|
640
|
-
var Link =
|
|
641
|
-
({ className, theme = "default", size = "md", ...props }, ref) => /* @__PURE__ */
|
|
1780
|
+
import * as React12 from "react";
|
|
1781
|
+
import { jsx as jsx21 } from "react/jsx-runtime";
|
|
1782
|
+
var Link = React12.forwardRef(
|
|
1783
|
+
({ className, theme = "default", size = "md", ...props }, ref) => /* @__PURE__ */ jsx21(
|
|
642
1784
|
"a",
|
|
643
1785
|
{
|
|
644
1786
|
ref,
|
|
@@ -650,10 +1792,10 @@ var Link = React8.forwardRef(
|
|
|
650
1792
|
Link.displayName = "Link";
|
|
651
1793
|
|
|
652
1794
|
// src/components/Chip/Chip.tsx
|
|
653
|
-
import * as
|
|
654
|
-
import { jsx as
|
|
655
|
-
var Chip =
|
|
656
|
-
({ className, tone = "neutral", ...props }, ref) => /* @__PURE__ */
|
|
1795
|
+
import * as React13 from "react";
|
|
1796
|
+
import { jsx as jsx22 } from "react/jsx-runtime";
|
|
1797
|
+
var Chip = React13.forwardRef(
|
|
1798
|
+
({ className, tone = "neutral", ...props }, ref) => /* @__PURE__ */ jsx22(
|
|
657
1799
|
"span",
|
|
658
1800
|
{
|
|
659
1801
|
ref,
|
|
@@ -664,36 +1806,128 @@ var Chip = React9.forwardRef(
|
|
|
664
1806
|
);
|
|
665
1807
|
Chip.displayName = "Chip";
|
|
666
1808
|
|
|
1809
|
+
// src/components/Checkbox/Checkbox.tsx
|
|
1810
|
+
import { Checkbox as CheckboxIcon, CheckboxChecked, Minus as Minus2 } from "@mirror-physics/fractal-icons";
|
|
1811
|
+
import { jsx as jsx23, jsxs as jsxs18 } from "react/jsx-runtime";
|
|
1812
|
+
function Checkbox({
|
|
1813
|
+
checked,
|
|
1814
|
+
indeterminate = false,
|
|
1815
|
+
onCheckedChange,
|
|
1816
|
+
className,
|
|
1817
|
+
disabled,
|
|
1818
|
+
onClick,
|
|
1819
|
+
onKeyDown,
|
|
1820
|
+
...props
|
|
1821
|
+
}) {
|
|
1822
|
+
return /* @__PURE__ */ jsx23(
|
|
1823
|
+
"button",
|
|
1824
|
+
{
|
|
1825
|
+
...props,
|
|
1826
|
+
className: cn(
|
|
1827
|
+
"fractal-checkbox",
|
|
1828
|
+
(checked || indeterminate) && "fractal-checkbox--checked",
|
|
1829
|
+
indeterminate && "fractal-checkbox--indeterminate",
|
|
1830
|
+
className
|
|
1831
|
+
),
|
|
1832
|
+
type: "button",
|
|
1833
|
+
role: "checkbox",
|
|
1834
|
+
"aria-checked": indeterminate ? "mixed" : checked,
|
|
1835
|
+
disabled,
|
|
1836
|
+
onClick: (event) => {
|
|
1837
|
+
onClick?.(event);
|
|
1838
|
+
if (!event.defaultPrevented) onCheckedChange(indeterminate || !checked);
|
|
1839
|
+
},
|
|
1840
|
+
onKeyDown: (event) => {
|
|
1841
|
+
onKeyDown?.(event);
|
|
1842
|
+
if (event.key === " " || event.key === "Enter") event.stopPropagation();
|
|
1843
|
+
},
|
|
1844
|
+
children: indeterminate ? /* @__PURE__ */ jsxs18("span", { className: "fractal-checkbox__indeterminate-icon", "aria-hidden": "true", children: [
|
|
1845
|
+
/* @__PURE__ */ jsx23(CheckboxIcon, { size: 18 }),
|
|
1846
|
+
/* @__PURE__ */ jsx23(Minus2, { className: "fractal-checkbox__indeterminate-mark", size: 12 })
|
|
1847
|
+
] }) : checked ? /* @__PURE__ */ jsx23(CheckboxChecked, { "aria-hidden": "true", size: 18 }) : /* @__PURE__ */ jsx23(CheckboxIcon, { "aria-hidden": "true", size: 18 })
|
|
1848
|
+
}
|
|
1849
|
+
);
|
|
1850
|
+
}
|
|
1851
|
+
|
|
1852
|
+
// src/components/Radio/Radio.tsx
|
|
1853
|
+
import { jsx as jsx24, jsxs as jsxs19 } from "react/jsx-runtime";
|
|
1854
|
+
function Radio({
|
|
1855
|
+
checked,
|
|
1856
|
+
className,
|
|
1857
|
+
description,
|
|
1858
|
+
disabled,
|
|
1859
|
+
label,
|
|
1860
|
+
onCheckedChange,
|
|
1861
|
+
...props
|
|
1862
|
+
}) {
|
|
1863
|
+
return /* @__PURE__ */ jsxs19("label", { className: cn("fractal-radio", disabled && "fractal-radio--disabled", className), children: [
|
|
1864
|
+
/* @__PURE__ */ jsx24(
|
|
1865
|
+
"input",
|
|
1866
|
+
{
|
|
1867
|
+
...props,
|
|
1868
|
+
checked,
|
|
1869
|
+
className: "fractal-radio__input",
|
|
1870
|
+
disabled,
|
|
1871
|
+
onChange: (event) => onCheckedChange?.(event.currentTarget.checked),
|
|
1872
|
+
type: "radio"
|
|
1873
|
+
}
|
|
1874
|
+
),
|
|
1875
|
+
/* @__PURE__ */ jsx24("span", { "aria-hidden": "true", className: "fractal-radio__control", children: /* @__PURE__ */ jsx24("span", { className: "fractal-radio__dot" }) }),
|
|
1876
|
+
/* @__PURE__ */ jsxs19("span", { className: "fractal-radio__content", children: [
|
|
1877
|
+
/* @__PURE__ */ jsx24("span", { className: "fractal-radio__label", children: label }),
|
|
1878
|
+
description && /* @__PURE__ */ jsx24("span", { className: "fractal-radio__description", children: description })
|
|
1879
|
+
] })
|
|
1880
|
+
] });
|
|
1881
|
+
}
|
|
1882
|
+
|
|
667
1883
|
// src/components/SortableTable/SortableTable.tsx
|
|
668
|
-
import { useMemo, useState as
|
|
1884
|
+
import { useMemo as useMemo2, useState as useState8 } from "react";
|
|
669
1885
|
import { ArrowUp, ArrowDown, ArrowsUpDown } from "@mirror-physics/fractal-icons";
|
|
670
|
-
import { jsx as
|
|
1886
|
+
import { jsx as jsx25, jsxs as jsxs20 } from "react/jsx-runtime";
|
|
671
1887
|
function SortableTable({
|
|
672
1888
|
columns,
|
|
673
1889
|
data,
|
|
1890
|
+
"aria-label": ariaLabel,
|
|
674
1891
|
emptyMessage,
|
|
675
1892
|
header,
|
|
676
1893
|
size = "md",
|
|
1894
|
+
embedded = false,
|
|
1895
|
+
layout = "fill",
|
|
1896
|
+
stickyHeader = false,
|
|
1897
|
+
stickyFirstColumn = false,
|
|
1898
|
+
maxHeight,
|
|
1899
|
+
overflowMenu,
|
|
677
1900
|
className,
|
|
1901
|
+
defaultSort,
|
|
678
1902
|
defaultSortKey = void 0,
|
|
679
1903
|
defaultSortDirection = null,
|
|
680
1904
|
sortKey: controlledKey,
|
|
681
1905
|
sortDirection: controlledDirection,
|
|
682
1906
|
onSortChange,
|
|
1907
|
+
pagination,
|
|
683
1908
|
highlightRow,
|
|
684
|
-
|
|
1909
|
+
selection,
|
|
1910
|
+
isRowDisabled,
|
|
1911
|
+
isRowSelectionDisabled,
|
|
1912
|
+
onRowClick,
|
|
1913
|
+
onRowDoubleClick,
|
|
1914
|
+
rowAction
|
|
685
1915
|
}) {
|
|
686
|
-
const [internalKey, setInternalKey] =
|
|
687
|
-
const [internalDirection, setInternalDirection] =
|
|
1916
|
+
const [internalKey, setInternalKey] = useState8(defaultSortKey ?? null);
|
|
1917
|
+
const [internalDirection, setInternalDirection] = useState8(defaultSortDirection);
|
|
688
1918
|
const isControlled = controlledKey !== void 0 && controlledDirection !== void 0;
|
|
689
1919
|
const activeKey = isControlled ? controlledKey : internalKey;
|
|
690
1920
|
const activeDirection = isControlled ? controlledDirection : internalDirection;
|
|
691
|
-
const
|
|
692
|
-
|
|
693
|
-
|
|
1921
|
+
const baselineKey = defaultSort?.key ?? null;
|
|
1922
|
+
const baselineDirection = defaultSort?.direction ?? null;
|
|
1923
|
+
const effectiveKey = activeKey && activeDirection ? activeKey : baselineKey;
|
|
1924
|
+
const effectiveDirection = activeKey && activeDirection ? activeDirection : baselineDirection;
|
|
1925
|
+
const sorted = useMemo2(() => {
|
|
1926
|
+
if (!effectiveKey || !effectiveDirection) return data;
|
|
1927
|
+
const col = columns.find((c) => c.key === effectiveKey);
|
|
694
1928
|
if (!col) return data;
|
|
695
1929
|
const accessor = col.sortAccessor ?? ((row) => {
|
|
696
|
-
const value = row[
|
|
1930
|
+
const value = row[effectiveKey];
|
|
697
1931
|
return typeof value === "string" || typeof value === "number" ? value : null;
|
|
698
1932
|
});
|
|
699
1933
|
const copy = [...data];
|
|
@@ -704,26 +1938,41 @@ function SortableTable({
|
|
|
704
1938
|
if (av == null) return 1;
|
|
705
1939
|
if (bv == null) return -1;
|
|
706
1940
|
if (typeof av === "number" && typeof bv === "number") {
|
|
707
|
-
return
|
|
1941
|
+
return effectiveDirection === "asc" ? av - bv : bv - av;
|
|
708
1942
|
}
|
|
709
1943
|
const as = String(av).toLowerCase();
|
|
710
1944
|
const bs = String(bv).toLowerCase();
|
|
711
|
-
if (as < bs) return
|
|
712
|
-
if (as > bs) return
|
|
1945
|
+
if (as < bs) return effectiveDirection === "asc" ? -1 : 1;
|
|
1946
|
+
if (as > bs) return effectiveDirection === "asc" ? 1 : -1;
|
|
713
1947
|
return 0;
|
|
714
1948
|
});
|
|
715
1949
|
return copy;
|
|
716
|
-
}, [data, columns,
|
|
1950
|
+
}, [data, columns, effectiveKey, effectiveDirection]);
|
|
1951
|
+
const visibleRows = useMemo2(() => {
|
|
1952
|
+
if (!pagination) return sorted;
|
|
1953
|
+
const pageSize = Math.max(1, pagination.pageSize);
|
|
1954
|
+
const totalPages = Math.max(1, Math.ceil(sorted.length / pageSize));
|
|
1955
|
+
const page = Math.min(Math.max(1, pagination.page), totalPages);
|
|
1956
|
+
const startIndex = (page - 1) * pageSize;
|
|
1957
|
+
return sorted.slice(startIndex, startIndex + pageSize);
|
|
1958
|
+
}, [pagination, sorted]);
|
|
1959
|
+
const selectedRows = selection ? sorted.filter(selection.isSelected) : [];
|
|
1960
|
+
const selectableRows = selection ? sorted.filter((row) => !isRowDisabled?.(row) && !isRowSelectionDisabled?.(row)) : [];
|
|
1961
|
+
const selectedRowCount = selection ? selectableRows.filter(selection.isSelected).length : 0;
|
|
1962
|
+
const allRowsSelected = selectableRows.length > 0 && selectedRowCount === selectableRows.length;
|
|
1963
|
+
const someRowsSelected = selectedRows.length > 0 && !allRowsSelected;
|
|
717
1964
|
const handleSortClick = (key) => {
|
|
718
1965
|
let nextDirection;
|
|
719
|
-
if (activeKey
|
|
1966
|
+
if (!activeKey || !activeDirection) {
|
|
1967
|
+
nextDirection = baselineKey === key && baselineDirection ? baselineDirection : "asc";
|
|
1968
|
+
} else if (activeKey !== key) {
|
|
720
1969
|
nextDirection = "asc";
|
|
1970
|
+
} else if (baselineKey === key && baselineDirection) {
|
|
1971
|
+
nextDirection = activeDirection === baselineDirection ? baselineDirection === "asc" ? "desc" : "asc" : null;
|
|
721
1972
|
} else if (activeDirection === "asc") {
|
|
722
1973
|
nextDirection = "desc";
|
|
723
|
-
} else if (activeDirection === "desc") {
|
|
724
|
-
nextDirection = null;
|
|
725
1974
|
} else {
|
|
726
|
-
nextDirection =
|
|
1975
|
+
nextDirection = null;
|
|
727
1976
|
}
|
|
728
1977
|
const nextKey = nextDirection === null ? null : key;
|
|
729
1978
|
if (isControlled) {
|
|
@@ -734,101 +1983,200 @@ function SortableTable({
|
|
|
734
1983
|
onSortChange?.(nextKey, nextDirection);
|
|
735
1984
|
}
|
|
736
1985
|
};
|
|
737
|
-
return /* @__PURE__ */
|
|
738
|
-
header && /* @__PURE__ */
|
|
739
|
-
|
|
740
|
-
/* @__PURE__ */
|
|
741
|
-
|
|
742
|
-
if (!col.sortable) {
|
|
743
|
-
return /* @__PURE__ */ jsx12(
|
|
744
|
-
"th",
|
|
745
|
-
{
|
|
746
|
-
className: "fractal-sortable-table-th",
|
|
747
|
-
style: { width: col.width },
|
|
748
|
-
children: col.header
|
|
749
|
-
},
|
|
750
|
-
col.key
|
|
751
|
-
);
|
|
752
|
-
}
|
|
753
|
-
return /* @__PURE__ */ jsx12(
|
|
1986
|
+
return /* @__PURE__ */ jsx25("div", { className: cn("fractal-table-layout", "fractal-sortable-table", `fractal-sortable-table--${size}`, embedded && "fractal-sortable-table--embedded", className), "data-overflow-menu": Boolean(overflowMenu), "data-table-layout": layout, "data-sticky-first": stickyFirstColumn, "data-sticky-header": stickyHeader, "data-table-selection": Boolean(selection), children: /* @__PURE__ */ jsxs20("div", { className: "fractal-sortable-table-surface", children: [
|
|
1987
|
+
header && /* @__PURE__ */ jsx25("div", { className: "fractal-sortable-table-header", children: header }),
|
|
1988
|
+
visibleRows.length === 0 ? /* @__PURE__ */ jsx25("div", { className: "fractal-sortable-table-empty", children: emptyMessage || "No data" }) : /* @__PURE__ */ jsx25(TableViewport, { maxHeight, label: ariaLabel || "Data table", children: /* @__PURE__ */ jsxs20("table", { "aria-label": ariaLabel, className: "fractal-sortable-table-table", children: [
|
|
1989
|
+
/* @__PURE__ */ jsx25("thead", { children: /* @__PURE__ */ jsxs20("tr", { className: "fractal-sortable-table-thead-row", children: [
|
|
1990
|
+
selection && /* @__PURE__ */ jsx25(
|
|
754
1991
|
"th",
|
|
755
1992
|
{
|
|
756
|
-
className: "fractal-sortable-table-th fractal-sortable-table-
|
|
757
|
-
|
|
758
|
-
|
|
759
|
-
|
|
1993
|
+
className: "fractal-sortable-table-th fractal-sortable-table-selection-cell",
|
|
1994
|
+
"data-pinned-column": "selection",
|
|
1995
|
+
scope: "col",
|
|
1996
|
+
children: /* @__PURE__ */ jsx25(
|
|
1997
|
+
Checkbox,
|
|
760
1998
|
{
|
|
761
|
-
|
|
762
|
-
|
|
763
|
-
|
|
764
|
-
|
|
765
|
-
)
|
|
766
|
-
|
|
767
|
-
|
|
768
|
-
|
|
769
|
-
|
|
770
|
-
|
|
771
|
-
|
|
1999
|
+
"aria-label": selection.selectAllLabel ?? "Select all rows",
|
|
2000
|
+
checked: allRowsSelected,
|
|
2001
|
+
disabled: selectableRows.length === 0 && selectedRows.length === 0,
|
|
2002
|
+
indeterminate: someRowsSelected,
|
|
2003
|
+
onCheckedChange: (checked) => {
|
|
2004
|
+
const rows = checked ? selectableRows : selectedRows;
|
|
2005
|
+
if (selection.onSelectAllChange) {
|
|
2006
|
+
selection.onSelectAllChange(rows, checked);
|
|
2007
|
+
return;
|
|
2008
|
+
}
|
|
2009
|
+
rows.forEach((row) => {
|
|
2010
|
+
if (selection.isSelected(row) !== checked) {
|
|
2011
|
+
selection.onSelectedChange(row, checked);
|
|
2012
|
+
}
|
|
2013
|
+
});
|
|
2014
|
+
}
|
|
772
2015
|
}
|
|
773
2016
|
)
|
|
774
|
-
}
|
|
775
|
-
|
|
776
|
-
)
|
|
777
|
-
|
|
778
|
-
|
|
2017
|
+
}
|
|
2018
|
+
),
|
|
2019
|
+
columns.map((col, columnIndex) => {
|
|
2020
|
+
const isActive = activeKey === col.key && activeDirection !== null;
|
|
2021
|
+
if (!col.sortable) {
|
|
2022
|
+
return /* @__PURE__ */ jsx25(
|
|
2023
|
+
"th",
|
|
2024
|
+
{
|
|
2025
|
+
className: "fractal-sortable-table-th",
|
|
2026
|
+
scope: "col",
|
|
2027
|
+
style: columnStyle(col),
|
|
2028
|
+
"data-pinned-column": columnIndex === 0 ? "data" : void 0,
|
|
2029
|
+
children: /* @__PURE__ */ jsx25(TableCellContent, { label: `${col.header} column`, children: col.header })
|
|
2030
|
+
},
|
|
2031
|
+
col.key
|
|
2032
|
+
);
|
|
2033
|
+
}
|
|
2034
|
+
return /* @__PURE__ */ jsx25(
|
|
2035
|
+
"th",
|
|
2036
|
+
{
|
|
2037
|
+
className: "fractal-sortable-table-th fractal-sortable-table-th--sortable",
|
|
2038
|
+
scope: "col",
|
|
2039
|
+
style: columnStyle(col),
|
|
2040
|
+
"data-pinned-column": columnIndex === 0 ? "data" : void 0,
|
|
2041
|
+
children: /* @__PURE__ */ jsx25(TableCellContent, { label: `${col.header} column`, children: /* @__PURE__ */ jsxs20(
|
|
2042
|
+
"button",
|
|
2043
|
+
{
|
|
2044
|
+
type: "button",
|
|
2045
|
+
className: cn(
|
|
2046
|
+
"fractal-sortable-table-sort-button",
|
|
2047
|
+
isActive && "fractal-sortable-table-sort-button--active"
|
|
2048
|
+
),
|
|
2049
|
+
onClick: () => handleSortClick(col.key),
|
|
2050
|
+
"aria-sort": isActive ? activeDirection === "asc" ? "ascending" : "descending" : "none",
|
|
2051
|
+
children: [
|
|
2052
|
+
/* @__PURE__ */ jsx25("span", { children: col.header }),
|
|
2053
|
+
/* @__PURE__ */ jsx25("span", { className: "fractal-sortable-table-sort-icon", "aria-hidden": "true", children: isActive && activeDirection === "asc" ? /* @__PURE__ */ jsx25(ArrowUp, { size: 14 }) : isActive && activeDirection === "desc" ? /* @__PURE__ */ jsx25(ArrowDown, { size: 14 }) : /* @__PURE__ */ jsx25(ArrowsUpDown, { size: 14 }) })
|
|
2054
|
+
]
|
|
2055
|
+
}
|
|
2056
|
+
) })
|
|
2057
|
+
},
|
|
2058
|
+
col.key
|
|
2059
|
+
);
|
|
2060
|
+
}),
|
|
2061
|
+
overflowMenu && /* @__PURE__ */ jsx25("th", { scope: "col", "aria-label": "Row actions", className: "fractal-sortable-table-th fractal-table-overflow-cell", "data-pinned-column": "overflow" })
|
|
2062
|
+
] }) }),
|
|
2063
|
+
/* @__PURE__ */ jsx25("tbody", { children: visibleRows.map((row, rowIndex) => {
|
|
779
2064
|
const highlighted = highlightRow?.(row, rowIndex) ?? false;
|
|
780
|
-
|
|
2065
|
+
const disabled = isRowDisabled?.(row) ?? false;
|
|
2066
|
+
const selectionDisabled = disabled || (isRowSelectionDisabled?.(row) ?? false);
|
|
2067
|
+
const interactive = !disabled && Boolean(onRowClick || onRowDoubleClick);
|
|
2068
|
+
const action = !disabled && rowAction ? {
|
|
2069
|
+
label: rowAction.label(row, rowIndex),
|
|
2070
|
+
icon: rowAction.icon(row, rowIndex)
|
|
2071
|
+
} : null;
|
|
2072
|
+
return /* @__PURE__ */ jsxs20(
|
|
781
2073
|
"tr",
|
|
782
2074
|
{
|
|
783
2075
|
className: cn(
|
|
784
2076
|
"fractal-sortable-table-row",
|
|
785
2077
|
highlighted && "fractal-sortable-table-row--highlighted",
|
|
786
|
-
|
|
2078
|
+
interactive && "fractal-sortable-table-row--interactive",
|
|
2079
|
+
disabled && "fractal-sortable-table-row--disabled"
|
|
787
2080
|
),
|
|
788
|
-
|
|
789
|
-
|
|
2081
|
+
"data-disabled": disabled || void 0,
|
|
2082
|
+
onClick: !disabled && onRowClick ? () => onRowClick(row, rowIndex) : void 0,
|
|
2083
|
+
onDoubleClick: !disabled && onRowDoubleClick ? () => onRowDoubleClick(row, rowIndex) : void 0,
|
|
2084
|
+
onKeyDown: interactive ? (event) => {
|
|
790
2085
|
if (event.key === "Enter" || event.key === " ") {
|
|
791
2086
|
event.preventDefault();
|
|
792
|
-
onRowClick
|
|
2087
|
+
const activateRow = onRowClick ?? onRowDoubleClick;
|
|
2088
|
+
activateRow?.(row, rowIndex);
|
|
793
2089
|
}
|
|
794
2090
|
} : void 0,
|
|
795
|
-
|
|
796
|
-
|
|
797
|
-
|
|
798
|
-
|
|
799
|
-
|
|
800
|
-
|
|
801
|
-
|
|
802
|
-
|
|
803
|
-
|
|
804
|
-
|
|
805
|
-
|
|
2091
|
+
"aria-label": action?.label,
|
|
2092
|
+
"aria-disabled": disabled || void 0,
|
|
2093
|
+
role: interactive ? "button" : void 0,
|
|
2094
|
+
tabIndex: interactive ? 0 : void 0,
|
|
2095
|
+
children: [
|
|
2096
|
+
selection && /* @__PURE__ */ jsx25("td", { className: "fractal-sortable-table-td fractal-sortable-table-selection-cell", "data-pinned-column": "selection", children: /* @__PURE__ */ jsx25(
|
|
2097
|
+
Checkbox,
|
|
2098
|
+
{
|
|
2099
|
+
"aria-label": selection.getRowLabel(row),
|
|
2100
|
+
checked: !selectionDisabled && selection.isSelected(row),
|
|
2101
|
+
disabled: selectionDisabled,
|
|
2102
|
+
onClick: (event) => event.stopPropagation(),
|
|
2103
|
+
onCheckedChange: (checked) => {
|
|
2104
|
+
if (!selectionDisabled) selection.onSelectedChange(row, checked);
|
|
2105
|
+
}
|
|
2106
|
+
}
|
|
2107
|
+
) }),
|
|
2108
|
+
columns.map((col, columnIndex) => /* @__PURE__ */ jsxs20(
|
|
2109
|
+
"td",
|
|
2110
|
+
{
|
|
2111
|
+
className: cn(
|
|
2112
|
+
"fractal-sortable-table-td",
|
|
2113
|
+
action && columnIndex === columns.length - 1 && "fractal-sortable-table-td--row-action"
|
|
2114
|
+
),
|
|
2115
|
+
style: { ...columnStyle(col), textAlign: col.align ?? "left" },
|
|
2116
|
+
"data-column-align": col.align,
|
|
2117
|
+
"data-pinned-column": columnIndex === 0 ? "data" : void 0,
|
|
2118
|
+
children: [
|
|
2119
|
+
/* @__PURE__ */ jsx25(TableCellContent, { label: `${col.header || "Value"}, row ${rowIndex + 1}`, children: col.render(row, rowIndex) }),
|
|
2120
|
+
action && columnIndex === columns.length - 1 && /* @__PURE__ */ jsx25("span", { className: "fractal-sortable-table-row-action", "aria-hidden": "true", children: /* @__PURE__ */ jsx25("span", { className: "fractal-sortable-table-row-action__icon", children: action.icon }) })
|
|
2121
|
+
]
|
|
2122
|
+
},
|
|
2123
|
+
col.key
|
|
2124
|
+
)),
|
|
2125
|
+
overflowMenu && /* @__PURE__ */ jsx25(
|
|
2126
|
+
"td",
|
|
2127
|
+
{
|
|
2128
|
+
className: "fractal-sortable-table-td fractal-table-overflow-cell",
|
|
2129
|
+
"data-pinned-column": "overflow",
|
|
2130
|
+
onClick: (event) => event.stopPropagation(),
|
|
2131
|
+
onDoubleClick: (event) => event.stopPropagation(),
|
|
2132
|
+
onKeyDown: (event) => event.stopPropagation(),
|
|
2133
|
+
children: /* @__PURE__ */ jsx25(TableOverflowMenu, { items: overflowMenu.items(row, rowIndex), label: overflowMenu.getLabel?.(row, rowIndex) ?? `Actions for row ${rowIndex + 1}`, disabled: disabled || overflowMenu.isDisabled?.(row, rowIndex), onSelect: (value) => overflowMenu.onSelect(value, row, rowIndex) })
|
|
2134
|
+
}
|
|
2135
|
+
)
|
|
2136
|
+
]
|
|
806
2137
|
},
|
|
807
2138
|
rowIndex
|
|
808
2139
|
);
|
|
809
2140
|
}) })
|
|
810
|
-
] })
|
|
2141
|
+
] }) })
|
|
811
2142
|
] }) });
|
|
812
2143
|
}
|
|
813
2144
|
|
|
814
2145
|
// src/components/Tabs/Tabs.tsx
|
|
815
|
-
import { useId, useRef as
|
|
816
|
-
import { jsx as
|
|
2146
|
+
import { useId as useId5, useLayoutEffect as useLayoutEffect4, useRef as useRef8, useState as useState9 } from "react";
|
|
2147
|
+
import { jsx as jsx26, jsxs as jsxs21 } from "react/jsx-runtime";
|
|
817
2148
|
function Tabs({
|
|
818
2149
|
items,
|
|
819
2150
|
defaultValue,
|
|
820
2151
|
value: controlledValue,
|
|
821
2152
|
onValueChange,
|
|
822
2153
|
className,
|
|
823
|
-
ariaLabel
|
|
2154
|
+
ariaLabel,
|
|
2155
|
+
divider = false,
|
|
2156
|
+
variant = "line"
|
|
824
2157
|
}) {
|
|
825
|
-
const reactId =
|
|
826
|
-
const [internalValue, setInternalValue] =
|
|
2158
|
+
const reactId = useId5();
|
|
2159
|
+
const [internalValue, setInternalValue] = useState9(
|
|
827
2160
|
defaultValue ?? items.find((i) => !i.disabled)?.id ?? items[0]?.id ?? ""
|
|
828
2161
|
);
|
|
829
2162
|
const isControlled = controlledValue !== void 0;
|
|
830
2163
|
const activeId = isControlled ? controlledValue : internalValue;
|
|
831
|
-
const
|
|
2164
|
+
const tabListRef = useRef8(null);
|
|
2165
|
+
const tabRefs = useRef8({});
|
|
2166
|
+
const [indicator, setIndicator] = useState9(null);
|
|
2167
|
+
useLayoutEffect4(() => {
|
|
2168
|
+
const updateIndicator = () => {
|
|
2169
|
+
const activeTab = tabRefs.current[activeId];
|
|
2170
|
+
if (!activeTab) return;
|
|
2171
|
+
setIndicator({ offset: activeTab.offsetLeft, width: activeTab.offsetWidth });
|
|
2172
|
+
};
|
|
2173
|
+
updateIndicator();
|
|
2174
|
+
const list = tabListRef.current;
|
|
2175
|
+
if (!list || typeof ResizeObserver === "undefined") return;
|
|
2176
|
+
const observer = new ResizeObserver(updateIndicator);
|
|
2177
|
+
observer.observe(list);
|
|
2178
|
+
return () => observer.disconnect();
|
|
2179
|
+
}, [activeId, items.length]);
|
|
832
2180
|
const selectTab = (id) => {
|
|
833
2181
|
if (isControlled) {
|
|
834
2182
|
onValueChange?.(id);
|
|
@@ -838,6 +2186,10 @@ function Tabs({
|
|
|
838
2186
|
}
|
|
839
2187
|
};
|
|
840
2188
|
const focusable = items.filter((i) => !i.disabled);
|
|
2189
|
+
const indicatorStyle = indicator ? {
|
|
2190
|
+
"--fractal-tabs-indicator-offset": `${indicator.offset}px`,
|
|
2191
|
+
"--fractal-tabs-indicator-width": `${indicator.width}px`
|
|
2192
|
+
} : void 0;
|
|
841
2193
|
const onKeyDown = (event) => {
|
|
842
2194
|
const currentIndex = focusable.findIndex((i) => i.id === activeId);
|
|
843
2195
|
if (currentIndex === -1) return;
|
|
@@ -863,41 +2215,52 @@ function Tabs({
|
|
|
863
2215
|
selectTab(nextId2);
|
|
864
2216
|
requestAnimationFrame(() => tabRefs.current[nextId2]?.focus());
|
|
865
2217
|
};
|
|
866
|
-
return /* @__PURE__ */
|
|
867
|
-
/* @__PURE__ */
|
|
868
|
-
|
|
869
|
-
|
|
870
|
-
|
|
871
|
-
|
|
872
|
-
"
|
|
873
|
-
|
|
874
|
-
|
|
875
|
-
|
|
876
|
-
|
|
877
|
-
id
|
|
878
|
-
|
|
879
|
-
|
|
880
|
-
|
|
881
|
-
|
|
882
|
-
|
|
883
|
-
|
|
884
|
-
|
|
885
|
-
|
|
886
|
-
|
|
887
|
-
|
|
888
|
-
|
|
889
|
-
|
|
890
|
-
|
|
891
|
-
|
|
892
|
-
|
|
893
|
-
|
|
894
|
-
|
|
895
|
-
|
|
2218
|
+
return /* @__PURE__ */ jsxs21("div", { className: cn("fractal-tabs", `fractal-tabs--${variant}`, divider && "fractal-tabs--divider", className), children: [
|
|
2219
|
+
/* @__PURE__ */ jsx26(
|
|
2220
|
+
"div",
|
|
2221
|
+
{
|
|
2222
|
+
ref: tabListRef,
|
|
2223
|
+
role: "tablist",
|
|
2224
|
+
"aria-label": ariaLabel,
|
|
2225
|
+
className: "fractal-tabs-list",
|
|
2226
|
+
"data-indicator-ready": indicator ? "true" : void 0,
|
|
2227
|
+
style: indicatorStyle,
|
|
2228
|
+
children: items.map((item) => {
|
|
2229
|
+
const isActive = item.id === activeId;
|
|
2230
|
+
const tabId = `${reactId}-tab-${item.id}`;
|
|
2231
|
+
const panelId = `${reactId}-panel-${item.id}`;
|
|
2232
|
+
return /* @__PURE__ */ jsx26(
|
|
2233
|
+
"button",
|
|
2234
|
+
{
|
|
2235
|
+
ref: (el) => {
|
|
2236
|
+
tabRefs.current[item.id] = el;
|
|
2237
|
+
},
|
|
2238
|
+
id: tabId,
|
|
2239
|
+
role: "tab",
|
|
2240
|
+
type: "button",
|
|
2241
|
+
"aria-selected": isActive,
|
|
2242
|
+
"aria-controls": panelId,
|
|
2243
|
+
tabIndex: isActive ? 0 : -1,
|
|
2244
|
+
disabled: item.disabled,
|
|
2245
|
+
className: cn(
|
|
2246
|
+
"fractal-tabs-trigger",
|
|
2247
|
+
isActive && "fractal-tabs-trigger--active",
|
|
2248
|
+
item.disabled && "fractal-tabs-trigger--disabled"
|
|
2249
|
+
),
|
|
2250
|
+
onClick: () => !item.disabled && selectTab(item.id),
|
|
2251
|
+
onKeyDown,
|
|
2252
|
+
children: item.label
|
|
2253
|
+
},
|
|
2254
|
+
item.id
|
|
2255
|
+
);
|
|
2256
|
+
})
|
|
2257
|
+
}
|
|
2258
|
+
),
|
|
896
2259
|
items.map((item) => {
|
|
897
2260
|
const tabId = `${reactId}-tab-${item.id}`;
|
|
898
2261
|
const panelId = `${reactId}-panel-${item.id}`;
|
|
899
2262
|
const isActive = item.id === activeId;
|
|
900
|
-
return /* @__PURE__ */
|
|
2263
|
+
return /* @__PURE__ */ jsx26(
|
|
901
2264
|
"div",
|
|
902
2265
|
{
|
|
903
2266
|
id: panelId,
|
|
@@ -913,10 +2276,112 @@ function Tabs({
|
|
|
913
2276
|
] });
|
|
914
2277
|
}
|
|
915
2278
|
|
|
2279
|
+
// src/components/ContentSwitcher/ContentSwitcher.tsx
|
|
2280
|
+
import * as React14 from "react";
|
|
2281
|
+
import { jsx as jsx27, jsxs as jsxs22 } from "react/jsx-runtime";
|
|
2282
|
+
function ContentSwitcher({ items, value, onValueChange, ariaLabel, fullWidth = false, className }) {
|
|
2283
|
+
const switcherRef = React14.useRef(null);
|
|
2284
|
+
const buttonRefs = React14.useRef([]);
|
|
2285
|
+
const indicatorMotionReadyRef = React14.useRef(false);
|
|
2286
|
+
const activeIndex = items.findIndex((item) => item.value === value);
|
|
2287
|
+
React14.useLayoutEffect(() => {
|
|
2288
|
+
const switcher = switcherRef.current;
|
|
2289
|
+
const activeButton = buttonRefs.current[activeIndex];
|
|
2290
|
+
let motionFrame = 0;
|
|
2291
|
+
if (!switcher || !activeButton) {
|
|
2292
|
+
switcher?.removeAttribute("data-indicator-ready");
|
|
2293
|
+
switcher?.removeAttribute("data-indicator-animate");
|
|
2294
|
+
indicatorMotionReadyRef.current = false;
|
|
2295
|
+
return;
|
|
2296
|
+
}
|
|
2297
|
+
const updateIndicator = () => {
|
|
2298
|
+
const switcherRect = switcher.getBoundingClientRect();
|
|
2299
|
+
const activeButtonRect = activeButton.getBoundingClientRect();
|
|
2300
|
+
switcher.style.setProperty("--fractal-content-switcher-indicator-x", `${activeButtonRect.left - switcherRect.left - switcher.clientLeft}px`);
|
|
2301
|
+
switcher.style.setProperty("--fractal-content-switcher-indicator-y", `${activeButtonRect.top - switcherRect.top - switcher.clientTop}px`);
|
|
2302
|
+
switcher.style.setProperty("--fractal-content-switcher-indicator-width", `${activeButtonRect.width}px`);
|
|
2303
|
+
switcher.style.setProperty("--fractal-content-switcher-indicator-height", `${activeButtonRect.height}px`);
|
|
2304
|
+
switcher.setAttribute("data-indicator-ready", "true");
|
|
2305
|
+
if (!indicatorMotionReadyRef.current && motionFrame === 0) {
|
|
2306
|
+
motionFrame = window.requestAnimationFrame(() => {
|
|
2307
|
+
indicatorMotionReadyRef.current = true;
|
|
2308
|
+
switcher.setAttribute("data-indicator-animate", "true");
|
|
2309
|
+
motionFrame = 0;
|
|
2310
|
+
});
|
|
2311
|
+
}
|
|
2312
|
+
};
|
|
2313
|
+
updateIndicator();
|
|
2314
|
+
if (typeof ResizeObserver === "undefined") {
|
|
2315
|
+
return () => {
|
|
2316
|
+
if (motionFrame !== 0) window.cancelAnimationFrame(motionFrame);
|
|
2317
|
+
};
|
|
2318
|
+
}
|
|
2319
|
+
const resizeObserver = new ResizeObserver(updateIndicator);
|
|
2320
|
+
resizeObserver.observe(switcher);
|
|
2321
|
+
buttonRefs.current.forEach((button) => {
|
|
2322
|
+
if (button) resizeObserver.observe(button);
|
|
2323
|
+
});
|
|
2324
|
+
return () => {
|
|
2325
|
+
resizeObserver.disconnect();
|
|
2326
|
+
if (motionFrame !== 0) window.cancelAnimationFrame(motionFrame);
|
|
2327
|
+
};
|
|
2328
|
+
}, [activeIndex, items.length]);
|
|
2329
|
+
const moveFocus = (index, direction) => {
|
|
2330
|
+
let nextIndex = index;
|
|
2331
|
+
do {
|
|
2332
|
+
nextIndex = (nextIndex + direction + items.length) % items.length;
|
|
2333
|
+
} while (items[nextIndex]?.disabled && nextIndex !== index);
|
|
2334
|
+
if (!items[nextIndex]?.disabled) {
|
|
2335
|
+
buttonRefs.current[nextIndex]?.focus();
|
|
2336
|
+
onValueChange(items[nextIndex].value);
|
|
2337
|
+
}
|
|
2338
|
+
};
|
|
2339
|
+
return /* @__PURE__ */ jsxs22(
|
|
2340
|
+
"div",
|
|
2341
|
+
{
|
|
2342
|
+
className: cn("fractal-content-switcher", fullWidth && "fractal-content-switcher--full-width", className),
|
|
2343
|
+
role: "group",
|
|
2344
|
+
"aria-label": ariaLabel,
|
|
2345
|
+
ref: switcherRef,
|
|
2346
|
+
children: [
|
|
2347
|
+
/* @__PURE__ */ jsx27("span", { className: "fractal-content-switcher__indicator", "aria-hidden": true }),
|
|
2348
|
+
items.map((item, index) => {
|
|
2349
|
+
const active = item.value === value;
|
|
2350
|
+
return /* @__PURE__ */ jsx27(
|
|
2351
|
+
"button",
|
|
2352
|
+
{
|
|
2353
|
+
className: cn("fractal-content-switcher__item", active && "fractal-content-switcher__item--active"),
|
|
2354
|
+
type: "button",
|
|
2355
|
+
"aria-pressed": active,
|
|
2356
|
+
disabled: item.disabled,
|
|
2357
|
+
onClick: () => onValueChange(item.value),
|
|
2358
|
+
onKeyDown: (event) => {
|
|
2359
|
+
if (event.key === "ArrowRight") {
|
|
2360
|
+
event.preventDefault();
|
|
2361
|
+
moveFocus(index, 1);
|
|
2362
|
+
}
|
|
2363
|
+
if (event.key === "ArrowLeft") {
|
|
2364
|
+
event.preventDefault();
|
|
2365
|
+
moveFocus(index, -1);
|
|
2366
|
+
}
|
|
2367
|
+
},
|
|
2368
|
+
ref: (element) => {
|
|
2369
|
+
buttonRefs.current[index] = element;
|
|
2370
|
+
},
|
|
2371
|
+
children: item.label
|
|
2372
|
+
},
|
|
2373
|
+
item.value
|
|
2374
|
+
);
|
|
2375
|
+
})
|
|
2376
|
+
]
|
|
2377
|
+
}
|
|
2378
|
+
);
|
|
2379
|
+
}
|
|
2380
|
+
|
|
916
2381
|
// src/components/Disclosure/Disclosure.tsx
|
|
917
|
-
import { useId as
|
|
918
|
-
import { ChevronRight, ChevronDown as ChevronDown2 } from "@mirror-physics/fractal-icons";
|
|
919
|
-
import { jsx as
|
|
2382
|
+
import { useId as useId6, useState as useState10 } from "react";
|
|
2383
|
+
import { ChevronRight as ChevronRight3, ChevronDown as ChevronDown2 } from "@mirror-physics/fractal-icons";
|
|
2384
|
+
import { jsx as jsx28, jsxs as jsxs23 } from "react/jsx-runtime";
|
|
920
2385
|
function Disclosure({
|
|
921
2386
|
title,
|
|
922
2387
|
meta,
|
|
@@ -924,16 +2389,18 @@ function Disclosure({
|
|
|
924
2389
|
defaultOpen = false,
|
|
925
2390
|
open: controlledOpen,
|
|
926
2391
|
onOpenChange,
|
|
2392
|
+
disabled = false,
|
|
927
2393
|
className,
|
|
928
2394
|
variant = "card"
|
|
929
2395
|
}) {
|
|
930
|
-
const reactId =
|
|
2396
|
+
const reactId = useId6();
|
|
931
2397
|
const headerId = `${reactId}-header`;
|
|
932
2398
|
const panelId = `${reactId}-panel`;
|
|
933
|
-
const [internalOpen, setInternalOpen] =
|
|
2399
|
+
const [internalOpen, setInternalOpen] = useState10(defaultOpen);
|
|
934
2400
|
const isControlled = controlledOpen !== void 0;
|
|
935
2401
|
const isOpen = isControlled ? controlledOpen : internalOpen;
|
|
936
2402
|
const toggle = () => {
|
|
2403
|
+
if (disabled) return;
|
|
937
2404
|
const next = !isOpen;
|
|
938
2405
|
if (isControlled) {
|
|
939
2406
|
onOpenChange?.(next);
|
|
@@ -942,17 +2409,18 @@ function Disclosure({
|
|
|
942
2409
|
onOpenChange?.(next);
|
|
943
2410
|
}
|
|
944
2411
|
};
|
|
945
|
-
return /* @__PURE__ */
|
|
2412
|
+
return /* @__PURE__ */ jsxs23(
|
|
946
2413
|
"div",
|
|
947
2414
|
{
|
|
948
2415
|
className: cn(
|
|
949
2416
|
"fractal-disclosure",
|
|
950
2417
|
variant === "card" && "fractal-disclosure--card",
|
|
951
2418
|
isOpen && "fractal-disclosure--open",
|
|
2419
|
+
disabled && "fractal-disclosure--disabled",
|
|
952
2420
|
className
|
|
953
2421
|
),
|
|
954
2422
|
children: [
|
|
955
|
-
/* @__PURE__ */
|
|
2423
|
+
/* @__PURE__ */ jsxs23(
|
|
956
2424
|
"button",
|
|
957
2425
|
{
|
|
958
2426
|
type: "button",
|
|
@@ -960,15 +2428,16 @@ function Disclosure({
|
|
|
960
2428
|
className: "fractal-disclosure-trigger",
|
|
961
2429
|
"aria-expanded": isOpen,
|
|
962
2430
|
"aria-controls": panelId,
|
|
2431
|
+
disabled,
|
|
963
2432
|
onClick: toggle,
|
|
964
2433
|
children: [
|
|
965
|
-
/* @__PURE__ */
|
|
966
|
-
/* @__PURE__ */
|
|
967
|
-
meta && /* @__PURE__ */
|
|
2434
|
+
/* @__PURE__ */ jsx28("span", { className: "fractal-disclosure-icon", "aria-hidden": "true", children: isOpen ? /* @__PURE__ */ jsx28(ChevronDown2, { size: 16 }) : /* @__PURE__ */ jsx28(ChevronRight3, { size: 16 }) }),
|
|
2435
|
+
/* @__PURE__ */ jsx28("span", { className: "fractal-disclosure-title", children: title }),
|
|
2436
|
+
meta && /* @__PURE__ */ jsx28("span", { className: "fractal-disclosure-meta", children: meta })
|
|
968
2437
|
]
|
|
969
2438
|
}
|
|
970
2439
|
),
|
|
971
|
-
/* @__PURE__ */
|
|
2440
|
+
/* @__PURE__ */ jsx28(
|
|
972
2441
|
"div",
|
|
973
2442
|
{
|
|
974
2443
|
id: panelId,
|
|
@@ -976,7 +2445,7 @@ function Disclosure({
|
|
|
976
2445
|
"aria-labelledby": headerId,
|
|
977
2446
|
className: "fractal-disclosure-panel",
|
|
978
2447
|
hidden: !isOpen,
|
|
979
|
-
children: /* @__PURE__ */
|
|
2448
|
+
children: /* @__PURE__ */ jsx28("div", { className: "fractal-disclosure-panel-inner", children })
|
|
980
2449
|
}
|
|
981
2450
|
)
|
|
982
2451
|
]
|
|
@@ -984,39 +2453,260 @@ function Disclosure({
|
|
|
984
2453
|
);
|
|
985
2454
|
}
|
|
986
2455
|
|
|
2456
|
+
// src/components/LatticeLoader/LatticeLoader.tsx
|
|
2457
|
+
import { jsx as jsx29 } from "react/jsx-runtime";
|
|
2458
|
+
var LATTICE_COUNT = 160;
|
|
2459
|
+
var WAVE_PERIOD = 80;
|
|
2460
|
+
function LatticeLoader({ className, label = "Loading", ...props }) {
|
|
2461
|
+
return /* @__PURE__ */ jsx29(
|
|
2462
|
+
"span",
|
|
2463
|
+
{
|
|
2464
|
+
"aria-label": label,
|
|
2465
|
+
className: cn("fractal-lattice-loader", className),
|
|
2466
|
+
role: "progressbar",
|
|
2467
|
+
...props,
|
|
2468
|
+
children: Array.from({ length: LATTICE_COUNT }, (_, index) => /* @__PURE__ */ jsx29(
|
|
2469
|
+
"span",
|
|
2470
|
+
{
|
|
2471
|
+
"aria-hidden": "true",
|
|
2472
|
+
className: "fractal-lattice-loader__cell",
|
|
2473
|
+
style: { "--fractal-lattice-index": index % WAVE_PERIOD }
|
|
2474
|
+
},
|
|
2475
|
+
index
|
|
2476
|
+
))
|
|
2477
|
+
}
|
|
2478
|
+
);
|
|
2479
|
+
}
|
|
2480
|
+
|
|
2481
|
+
// src/components/Ghost/Ghost.tsx
|
|
2482
|
+
import { jsx as jsx30, jsxs as jsxs24 } from "react/jsx-runtime";
|
|
2483
|
+
var toCssLength = (value) => typeof value === "number" ? `${value}px` : value;
|
|
2484
|
+
function Ghost({ className, width, height, radius, style, ...props }) {
|
|
2485
|
+
return /* @__PURE__ */ jsx30(
|
|
2486
|
+
"div",
|
|
2487
|
+
{
|
|
2488
|
+
"aria-hidden": "true",
|
|
2489
|
+
className: cn("fractal-ghost", className),
|
|
2490
|
+
style: {
|
|
2491
|
+
width: toCssLength(width),
|
|
2492
|
+
height: toCssLength(height),
|
|
2493
|
+
borderRadius: toCssLength(radius),
|
|
2494
|
+
...style
|
|
2495
|
+
},
|
|
2496
|
+
...props
|
|
2497
|
+
}
|
|
2498
|
+
);
|
|
2499
|
+
}
|
|
2500
|
+
function GhostLine({ className, size = "md", width = "100%", ...props }) {
|
|
2501
|
+
return /* @__PURE__ */ jsx30(Ghost, { className: cn("fractal-ghost-line", `fractal-ghost-line--${size}`, className), width, ...props });
|
|
2502
|
+
}
|
|
2503
|
+
function ButtonGhost({ className, size = "lg", controlSize, iconOnly = false, width, ...props }) {
|
|
2504
|
+
return /* @__PURE__ */ jsx30(Ghost, { "data-control-size": controlSize ?? size, className: cn("fractal-ghost-button", `fractal-ghost-button--${size}`, iconOnly && "fractal-ghost-button--icon-only", className), width, ...props });
|
|
2505
|
+
}
|
|
2506
|
+
function CardGhost({ className, lines = 3, showHeader = true, ...props }) {
|
|
2507
|
+
return /* @__PURE__ */ jsxs24("div", { "aria-hidden": "true", className: cn("fractal-ghost-card", className), ...props, children: [
|
|
2508
|
+
showHeader && /* @__PURE__ */ jsx30(GhostLine, { width: "38%" }),
|
|
2509
|
+
/* @__PURE__ */ jsx30("div", { className: "fractal-ghost-stack", children: Array.from({ length: lines }, (_, index) => /* @__PURE__ */ jsx30(GhostLine, { width: index === lines - 1 ? "62%" : "100%" }, index)) })
|
|
2510
|
+
] });
|
|
2511
|
+
}
|
|
2512
|
+
function DataTableGhost({
|
|
2513
|
+
className,
|
|
2514
|
+
showHeader = true,
|
|
2515
|
+
headers,
|
|
2516
|
+
columns = 4,
|
|
2517
|
+
rows = 5,
|
|
2518
|
+
columnWidths,
|
|
2519
|
+
size = "md",
|
|
2520
|
+
...props
|
|
2521
|
+
}) {
|
|
2522
|
+
const cells = Array.from({ length: columns }, (_, index) => index);
|
|
2523
|
+
return /* @__PURE__ */ jsx30("div", { "aria-busy": "true", "aria-label": "Loading table", className: cn("fractal-ghost-table", `fractal-ghost-table--${size}`, className), role: "status", ...props, children: /* @__PURE__ */ jsxs24("table", { className: "fractal-ghost-table__table", children: [
|
|
2524
|
+
(showHeader || headers) && /* @__PURE__ */ jsx30("thead", { children: /* @__PURE__ */ jsx30("tr", { className: "fractal-ghost-table__head-row", children: cells.map((index) => /* @__PURE__ */ jsx30("th", { style: { width: columnWidths?.[index] }, children: headers?.[index] ?? /* @__PURE__ */ jsx30(GhostLine, { size: "sm", width: index === columns - 1 ? "62%" : "76%" }) }, index)) }) }),
|
|
2525
|
+
/* @__PURE__ */ jsx30("tbody", { children: Array.from({ length: rows }, (_, rowIndex) => /* @__PURE__ */ jsx30("tr", { className: "fractal-ghost-table__row", children: cells.map((columnIndex) => /* @__PURE__ */ jsx30("td", { style: { width: columnWidths?.[columnIndex] }, children: /* @__PURE__ */ jsx30(GhostLine, { width: `${[72, 54, 82, 63, 46][(rowIndex + columnIndex) % 5]}%` }) }, columnIndex)) }, rowIndex)) })
|
|
2526
|
+
] }) });
|
|
2527
|
+
}
|
|
2528
|
+
function InputGhost({ className, labelWidth = "26%", ...props }) {
|
|
2529
|
+
return /* @__PURE__ */ jsx30(FormFieldGhost, { className, labelWidth, ...props });
|
|
2530
|
+
}
|
|
2531
|
+
function TextareaGhost({ className, labelWidth = "26%", ...props }) {
|
|
2532
|
+
return /* @__PURE__ */ jsx30(FormFieldGhost, { className, labelWidth, multiline: true, ...props });
|
|
2533
|
+
}
|
|
2534
|
+
function LabelGhost({ className, width = "26%", ...props }) {
|
|
2535
|
+
return /* @__PURE__ */ jsx30(GhostLine, { className: cn("fractal-ghost-label", className), size: "sm", width, ...props });
|
|
2536
|
+
}
|
|
2537
|
+
function FormFieldGhost({ className, labelWidth = "26%", multiline = false, controlSize = "lg", ...props }) {
|
|
2538
|
+
return /* @__PURE__ */ jsxs24("div", { "aria-hidden": "true", "data-control-size": controlSize, className: cn("fractal-ghost-field", className), ...props, children: [
|
|
2539
|
+
/* @__PURE__ */ jsx30(LabelGhost, { width: labelWidth }),
|
|
2540
|
+
/* @__PURE__ */ jsx30(Ghost, { className: cn("fractal-ghost-field__control", multiline && "fractal-ghost-field__control--multiline") })
|
|
2541
|
+
] });
|
|
2542
|
+
}
|
|
2543
|
+
function AlertGhost({ className, ...props }) {
|
|
2544
|
+
return /* @__PURE__ */ jsxs24("div", { "aria-hidden": "true", className: cn("fractal-ghost-alert", className), ...props, children: [
|
|
2545
|
+
/* @__PURE__ */ jsx30(GhostLine, { width: "30%" }),
|
|
2546
|
+
/* @__PURE__ */ jsx30(GhostLine, { size: "sm", width: "78%" })
|
|
2547
|
+
] });
|
|
2548
|
+
}
|
|
2549
|
+
function CheckboxGhost({ className, ...props }) {
|
|
2550
|
+
return /* @__PURE__ */ jsxs24("div", { "aria-hidden": "true", className: cn("fractal-ghost-choice", className), ...props, children: [
|
|
2551
|
+
/* @__PURE__ */ jsx30(Ghost, { className: "fractal-ghost-choice__control" }),
|
|
2552
|
+
/* @__PURE__ */ jsx30(GhostLine, { width: "42%" })
|
|
2553
|
+
] });
|
|
2554
|
+
}
|
|
2555
|
+
var ToggleGhost = CheckboxGhost;
|
|
2556
|
+
function ChipGhost({ className, width = 74, ...props }) {
|
|
2557
|
+
return /* @__PURE__ */ jsx30(Ghost, { className: cn("fractal-ghost-chip", className), height: 24, width, ...props });
|
|
2558
|
+
}
|
|
2559
|
+
function LinkGhost({ className, width = 96, ...props }) {
|
|
2560
|
+
return /* @__PURE__ */ jsx30(GhostLine, { className: cn("fractal-ghost-link", className), size: "sm", width, ...props });
|
|
2561
|
+
}
|
|
2562
|
+
var TextButtonGhost = LinkGhost;
|
|
2563
|
+
function DropdownGhost({ className, controlSize = "lg", ...props }) {
|
|
2564
|
+
return /* @__PURE__ */ jsxs24("div", { "aria-hidden": "true", "data-control-size": controlSize, className: cn("fractal-ghost-dropdown", className), ...props, children: [
|
|
2565
|
+
/* @__PURE__ */ jsx30(GhostLine, { width: "38%" }),
|
|
2566
|
+
/* @__PURE__ */ jsx30(Ghost, { className: "fractal-ghost-dropdown__chevron" })
|
|
2567
|
+
] });
|
|
2568
|
+
}
|
|
2569
|
+
function ContentSwitcherGhost({ className, options = 3, ...props }) {
|
|
2570
|
+
return /* @__PURE__ */ jsx30("div", { "aria-hidden": "true", className: cn("fractal-ghost-switcher", className), ...props, children: Array.from({ length: options }, (_, index) => /* @__PURE__ */ jsx30(Ghost, {}, index)) });
|
|
2571
|
+
}
|
|
2572
|
+
var TabsGhost = ContentSwitcherGhost;
|
|
2573
|
+
function DisclosureGhost({ className, ...props }) {
|
|
2574
|
+
return /* @__PURE__ */ jsxs24("div", { "aria-hidden": "true", className: cn("fractal-ghost-disclosure", className), ...props, children: [
|
|
2575
|
+
/* @__PURE__ */ jsx30(Ghost, { className: "fractal-ghost-disclosure__icon" }),
|
|
2576
|
+
/* @__PURE__ */ jsx30(GhostLine, { width: "42%" })
|
|
2577
|
+
] });
|
|
2578
|
+
}
|
|
2579
|
+
function PaginationGhost({ className, pages = 5, ...props }) {
|
|
2580
|
+
return /* @__PURE__ */ jsx30("div", { "aria-hidden": "true", className: cn("fractal-ghost-pagination", className), ...props, children: Array.from({ length: pages }, (_, index) => /* @__PURE__ */ jsx30(Ghost, {}, index)) });
|
|
2581
|
+
}
|
|
2582
|
+
function FileDropzoneGhost({ className, ...props }) {
|
|
2583
|
+
return /* @__PURE__ */ jsxs24("div", { "aria-hidden": "true", className: cn("fractal-ghost-dropzone", className), ...props, children: [
|
|
2584
|
+
/* @__PURE__ */ jsx30(Ghost, { className: "fractal-ghost-dropzone__icon" }),
|
|
2585
|
+
/* @__PURE__ */ jsx30(GhostLine, { width: "26%" }),
|
|
2586
|
+
/* @__PURE__ */ jsx30(GhostLine, { size: "sm", width: "46%" })
|
|
2587
|
+
] });
|
|
2588
|
+
}
|
|
2589
|
+
function PromptCardGhost({ className, ...props }) {
|
|
2590
|
+
return /* @__PURE__ */ jsx30(CardGhost, { className: cn("fractal-ghost-prompt-card", className), lines: 4, ...props });
|
|
2591
|
+
}
|
|
2592
|
+
function ConversationGhost({
|
|
2593
|
+
className,
|
|
2594
|
+
"aria-label": ariaLabel = "Loading conversation",
|
|
2595
|
+
...props
|
|
2596
|
+
}) {
|
|
2597
|
+
return /* @__PURE__ */ jsxs24(
|
|
2598
|
+
"div",
|
|
2599
|
+
{
|
|
2600
|
+
"aria-busy": "true",
|
|
2601
|
+
"aria-label": ariaLabel,
|
|
2602
|
+
className: cn("fractal-ghost-conversation", className),
|
|
2603
|
+
role: "status",
|
|
2604
|
+
...props,
|
|
2605
|
+
children: [
|
|
2606
|
+
/* @__PURE__ */ jsx30("div", { "aria-hidden": "true", className: "fractal-ghost-conversation__message fractal-ghost-conversation__message--user", children: /* @__PURE__ */ jsxs24("div", { className: "fractal-ghost-conversation__bubble", children: [
|
|
2607
|
+
/* @__PURE__ */ jsx30(GhostLine, { width: "100%" }),
|
|
2608
|
+
/* @__PURE__ */ jsx30(GhostLine, { width: "86%" }),
|
|
2609
|
+
/* @__PURE__ */ jsx30(GhostLine, { width: "64%" })
|
|
2610
|
+
] }) }),
|
|
2611
|
+
/* @__PURE__ */ jsxs24("div", { "aria-hidden": "true", className: "fractal-ghost-conversation__message fractal-ghost-conversation__message--assistant", children: [
|
|
2612
|
+
/* @__PURE__ */ jsx30(GhostLine, { width: "92%" }),
|
|
2613
|
+
/* @__PURE__ */ jsx30(GhostLine, { width: "78%" }),
|
|
2614
|
+
/* @__PURE__ */ jsx30(GhostLine, { width: "58%" })
|
|
2615
|
+
] })
|
|
2616
|
+
]
|
|
2617
|
+
}
|
|
2618
|
+
);
|
|
2619
|
+
}
|
|
2620
|
+
function SortableTableGhost(props) {
|
|
2621
|
+
return /* @__PURE__ */ jsx30(DataTableGhost, { ...props });
|
|
2622
|
+
}
|
|
2623
|
+
function SidebarGhost({ className, items = 6, ...props }) {
|
|
2624
|
+
return /* @__PURE__ */ jsxs24("aside", { "aria-hidden": "true", className: cn("fractal-ghost-sidebar", className), ...props, children: [
|
|
2625
|
+
/* @__PURE__ */ jsx30(Ghost, { className: "fractal-ghost-sidebar__brand" }),
|
|
2626
|
+
/* @__PURE__ */ jsx30("div", { className: "fractal-ghost-sidebar__items", children: Array.from({ length: items }, (_, index) => /* @__PURE__ */ jsxs24("div", { className: "fractal-ghost-sidebar__item", children: [
|
|
2627
|
+
/* @__PURE__ */ jsx30(Ghost, {}),
|
|
2628
|
+
/* @__PURE__ */ jsx30(GhostLine, { width: `${[54, 68, 44, 61][index % 4]}%` })
|
|
2629
|
+
] }, index)) })
|
|
2630
|
+
] });
|
|
2631
|
+
}
|
|
2632
|
+
function ModalGhost({ className, title, lines = 3, ...props }) {
|
|
2633
|
+
return /* @__PURE__ */ jsx30(SurfaceGhost, { className: cn("fractal-ghost-modal", className), title, lines, ...props });
|
|
2634
|
+
}
|
|
2635
|
+
function SidePanelGhost({ className, title, lines = 5, ...props }) {
|
|
2636
|
+
return /* @__PURE__ */ jsx30(SurfaceGhost, { className: cn("fractal-ghost-side-panel", className), title, lines, ...props });
|
|
2637
|
+
}
|
|
2638
|
+
function SurfaceGhost({ className, title, lines = 3, ...props }) {
|
|
2639
|
+
return /* @__PURE__ */ jsxs24("div", { "aria-hidden": "true", className: cn("fractal-ghost-surface", className), ...props, children: [
|
|
2640
|
+
/* @__PURE__ */ jsxs24("div", { className: "fractal-ghost-surface__header", children: [
|
|
2641
|
+
/* @__PURE__ */ jsx30(GhostLine, { width: "42%" }),
|
|
2642
|
+
/* @__PURE__ */ jsx30(Ghost, { className: "fractal-ghost-surface__close" })
|
|
2643
|
+
] }),
|
|
2644
|
+
title && /* @__PURE__ */ jsx30("div", { className: "fractal-ghost-surface__title", children: title }),
|
|
2645
|
+
/* @__PURE__ */ jsx30("div", { className: "fractal-ghost-stack", children: Array.from({ length: lines }, (_, index) => /* @__PURE__ */ jsx30(GhostLine, { width: index === lines - 1 ? "64%" : "100%" }, index)) })
|
|
2646
|
+
] });
|
|
2647
|
+
}
|
|
2648
|
+
|
|
987
2649
|
// src/components/Sidebar/Sidebar.tsx
|
|
988
|
-
import * as
|
|
989
|
-
import { jsx as
|
|
990
|
-
var Sidebar =
|
|
991
|
-
({ className, width, style, ...props }, ref) => /* @__PURE__ */
|
|
2650
|
+
import * as React15 from "react";
|
|
2651
|
+
import { Fragment as Fragment3, jsx as jsx31, jsxs as jsxs25 } from "react/jsx-runtime";
|
|
2652
|
+
var Sidebar = React15.forwardRef(
|
|
2653
|
+
({ className, width, compact = false, style, ...props }, ref) => /* @__PURE__ */ jsx31(
|
|
992
2654
|
"aside",
|
|
993
2655
|
{
|
|
994
2656
|
ref,
|
|
995
2657
|
className: cn("fractal-sidebar", className),
|
|
2658
|
+
"data-compact": compact || void 0,
|
|
996
2659
|
style: { ...style, ...width ? { "--fractal-sidebar-width": width } : {} },
|
|
997
2660
|
...props
|
|
998
2661
|
}
|
|
999
2662
|
)
|
|
1000
2663
|
);
|
|
1001
2664
|
Sidebar.displayName = "Sidebar";
|
|
1002
|
-
var SidebarHeader =
|
|
1003
|
-
({ className, ...props }, ref) => /* @__PURE__ */
|
|
2665
|
+
var SidebarHeader = React15.forwardRef(
|
|
2666
|
+
({ className, ...props }, ref) => /* @__PURE__ */ jsx31("div", { ref, className: cn("fractal-sidebar__header", className), ...props })
|
|
1004
2667
|
);
|
|
1005
2668
|
SidebarHeader.displayName = "SidebarHeader";
|
|
1006
|
-
var SidebarBrand =
|
|
1007
|
-
({ className, type = "button", ...props }, ref) => /* @__PURE__ */
|
|
2669
|
+
var SidebarBrand = React15.forwardRef(
|
|
2670
|
+
({ className, type = "button", ...props }, ref) => /* @__PURE__ */ jsx31("button", { ref, type, className: cn("fractal-sidebar__brand", className), ...props })
|
|
1008
2671
|
);
|
|
1009
2672
|
SidebarBrand.displayName = "SidebarBrand";
|
|
1010
|
-
|
|
1011
|
-
|
|
2673
|
+
function SidebarAccountMenu({
|
|
2674
|
+
name,
|
|
2675
|
+
items,
|
|
2676
|
+
onSelect,
|
|
2677
|
+
triggerLabel = "Account menu",
|
|
2678
|
+
icon,
|
|
2679
|
+
className
|
|
2680
|
+
}) {
|
|
2681
|
+
return /* @__PURE__ */ jsx31(
|
|
2682
|
+
Dropdown,
|
|
2683
|
+
{
|
|
2684
|
+
align: "left",
|
|
2685
|
+
className: cn("fractal-sidebar__account", className),
|
|
2686
|
+
items,
|
|
2687
|
+
onSelect,
|
|
2688
|
+
panelClassName: "fractal-sidebar__account-panel",
|
|
2689
|
+
selectedValue: "",
|
|
2690
|
+
triggerClassName: "fractal-sidebar__account-trigger",
|
|
2691
|
+
triggerContent: /* @__PURE__ */ jsxs25(Fragment3, { children: [
|
|
2692
|
+
icon && /* @__PURE__ */ jsx31("span", { className: "fractal-sidebar__account-icon", "aria-hidden": "true", children: icon }),
|
|
2693
|
+
/* @__PURE__ */ jsx31("span", { className: "fractal-sidebar__account-name", children: name })
|
|
2694
|
+
] }),
|
|
2695
|
+
triggerLabel,
|
|
2696
|
+
triggerVariant: "tertiary"
|
|
2697
|
+
}
|
|
2698
|
+
);
|
|
2699
|
+
}
|
|
2700
|
+
var SidebarNav = React15.forwardRef(
|
|
2701
|
+
({ className, ...props }, ref) => /* @__PURE__ */ jsx31("nav", { ref, className: cn("fractal-sidebar__nav", className), ...props })
|
|
1012
2702
|
);
|
|
1013
2703
|
SidebarNav.displayName = "SidebarNav";
|
|
1014
|
-
var SidebarSection =
|
|
1015
|
-
({ className, ...props }, ref) => /* @__PURE__ */
|
|
2704
|
+
var SidebarSection = React15.forwardRef(
|
|
2705
|
+
({ className, ...props }, ref) => /* @__PURE__ */ jsx31("div", { ref, className: cn("fractal-sidebar__section", className), ...props })
|
|
1016
2706
|
);
|
|
1017
2707
|
SidebarSection.displayName = "SidebarSection";
|
|
1018
|
-
var SidebarNavItem =
|
|
1019
|
-
({ active = false, icon, endAdornment, className, type = "button", children, ...props }, ref) => /* @__PURE__ */
|
|
2708
|
+
var SidebarNavItem = React15.forwardRef(
|
|
2709
|
+
({ active = false, icon, endAdornment, className, type = "button", children, ...props }, ref) => /* @__PURE__ */ jsxs25(
|
|
1020
2710
|
"button",
|
|
1021
2711
|
{
|
|
1022
2712
|
ref,
|
|
@@ -1026,28 +2716,60 @@ var SidebarNavItem = React10.forwardRef(
|
|
|
1026
2716
|
"aria-current": active ? "page" : void 0,
|
|
1027
2717
|
...props,
|
|
1028
2718
|
children: [
|
|
1029
|
-
icon && /* @__PURE__ */
|
|
1030
|
-
/* @__PURE__ */
|
|
1031
|
-
endAdornment && /* @__PURE__ */
|
|
2719
|
+
icon && /* @__PURE__ */ jsx31("span", { className: "fractal-sidebar__nav-item-icon", "aria-hidden": "true", children: icon }),
|
|
2720
|
+
/* @__PURE__ */ jsx31("span", { className: "fractal-sidebar__nav-item-label", children }),
|
|
2721
|
+
endAdornment && /* @__PURE__ */ jsx31("span", { className: "fractal-sidebar__nav-item-end", children: endAdornment })
|
|
1032
2722
|
]
|
|
1033
2723
|
}
|
|
1034
2724
|
)
|
|
1035
2725
|
);
|
|
1036
2726
|
SidebarNavItem.displayName = "SidebarNavItem";
|
|
1037
|
-
var SidebarFooter =
|
|
1038
|
-
({ className, ...props }, ref) => /* @__PURE__ */
|
|
2727
|
+
var SidebarFooter = React15.forwardRef(
|
|
2728
|
+
({ className, ...props }, ref) => /* @__PURE__ */ jsx31("div", { ref, className: cn("fractal-sidebar__footer", className), ...props })
|
|
1039
2729
|
);
|
|
1040
2730
|
SidebarFooter.displayName = "SidebarFooter";
|
|
1041
2731
|
|
|
1042
2732
|
// src/components/SidePanel/SidePanel.tsx
|
|
1043
|
-
import
|
|
1044
|
-
import {
|
|
1045
|
-
import {
|
|
1046
|
-
|
|
2733
|
+
import * as React16 from "react";
|
|
2734
|
+
import { createPortal as createPortal4 } from "react-dom";
|
|
2735
|
+
import { Close as Close3 } from "@mirror-physics/fractal-icons";
|
|
2736
|
+
import { jsx as jsx32, jsxs as jsxs26 } from "react/jsx-runtime";
|
|
2737
|
+
function SidePanel({ open, onClose, title, description, children, footer, size = "md", loading = false, loadingLabel = "Loading", className }) {
|
|
1047
2738
|
useEscapeDismiss(80, onClose, open);
|
|
2739
|
+
const bodyRef = React16.useRef(null);
|
|
2740
|
+
const [scrollEdges, setScrollEdges] = React16.useState({ above: false, below: false });
|
|
2741
|
+
React16.useLayoutEffect(() => {
|
|
2742
|
+
const body = bodyRef.current;
|
|
2743
|
+
if (!open || !body) return;
|
|
2744
|
+
const measure = () => {
|
|
2745
|
+
const maxScroll = Math.max(0, body.scrollHeight - body.clientHeight);
|
|
2746
|
+
const top = Math.max(0, Math.min(body.scrollTop, maxScroll));
|
|
2747
|
+
const above = maxScroll > 1 && top > 0;
|
|
2748
|
+
const below = maxScroll - top > 1;
|
|
2749
|
+
setScrollEdges((previous) => previous.above === above && previous.below === below ? previous : { above, below });
|
|
2750
|
+
};
|
|
2751
|
+
const resize = new ResizeObserver(measure);
|
|
2752
|
+
const observeContent = () => {
|
|
2753
|
+
resize.disconnect();
|
|
2754
|
+
resize.observe(body);
|
|
2755
|
+
for (const child of body.children) resize.observe(child);
|
|
2756
|
+
measure();
|
|
2757
|
+
};
|
|
2758
|
+
const mutations = new MutationObserver(observeContent);
|
|
2759
|
+
mutations.observe(body, { childList: true, subtree: true, characterData: true, attributes: true });
|
|
2760
|
+
body.addEventListener("scroll", measure, { passive: true });
|
|
2761
|
+
body.addEventListener("load", measure, true);
|
|
2762
|
+
observeContent();
|
|
2763
|
+
return () => {
|
|
2764
|
+
resize.disconnect();
|
|
2765
|
+
mutations.disconnect();
|
|
2766
|
+
body.removeEventListener("scroll", measure);
|
|
2767
|
+
body.removeEventListener("load", measure, true);
|
|
2768
|
+
};
|
|
2769
|
+
}, [open, loading]);
|
|
1048
2770
|
if (!open) return null;
|
|
1049
|
-
return
|
|
1050
|
-
/* @__PURE__ */
|
|
2771
|
+
return createPortal4(
|
|
2772
|
+
/* @__PURE__ */ jsx32("div", { className: "fractal-side-panel-overlay", onMouseDown: onClose, children: /* @__PURE__ */ jsxs26(
|
|
1051
2773
|
"aside",
|
|
1052
2774
|
{
|
|
1053
2775
|
className: cn("fractal-side-panel", `fractal-side-panel--${size}`, className),
|
|
@@ -1056,15 +2778,15 @@ function SidePanel({ open, onClose, title, description, children, footer, size =
|
|
|
1056
2778
|
role: "dialog",
|
|
1057
2779
|
onMouseDown: (event) => event.stopPropagation(),
|
|
1058
2780
|
children: [
|
|
1059
|
-
/* @__PURE__ */
|
|
1060
|
-
/* @__PURE__ */
|
|
1061
|
-
/* @__PURE__ */
|
|
1062
|
-
description && /* @__PURE__ */
|
|
2781
|
+
/* @__PURE__ */ jsxs26("header", { className: "fractal-side-panel__header", "data-scroll-divider": scrollEdges.above, children: [
|
|
2782
|
+
/* @__PURE__ */ jsxs26("div", { className: "fractal-side-panel__heading", children: [
|
|
2783
|
+
typeof title === "string" ? /* @__PURE__ */ jsx32("h2", { className: "fractal-side-panel__title", children: title }) : /* @__PURE__ */ jsx32("div", { className: "fractal-side-panel__title", children: title }),
|
|
2784
|
+
description && /* @__PURE__ */ jsx32("p", { className: "fractal-side-panel__description", children: description })
|
|
1063
2785
|
] }),
|
|
1064
|
-
/* @__PURE__ */
|
|
2786
|
+
/* @__PURE__ */ jsx32("button", { type: "button", className: "fractal-side-panel__close", "aria-label": "Close panel", onClick: onClose, children: /* @__PURE__ */ jsx32(Close3, { size: 18 }) })
|
|
1065
2787
|
] }),
|
|
1066
|
-
/* @__PURE__ */
|
|
1067
|
-
footer && /* @__PURE__ */
|
|
2788
|
+
/* @__PURE__ */ jsx32("div", { ref: bodyRef, "aria-busy": loading || void 0, className: cn("fractal-side-panel__body", loading && "fractal-side-panel__body--loading"), children: loading ? /* @__PURE__ */ jsx32(UILoader, { label: loadingLabel }) : children }),
|
|
2789
|
+
footer && /* @__PURE__ */ jsx32("footer", { className: "fractal-side-panel__footer", "data-scroll-divider": scrollEdges.below, children: footer })
|
|
1068
2790
|
]
|
|
1069
2791
|
}
|
|
1070
2792
|
) }),
|
|
@@ -1073,17 +2795,57 @@ function SidePanel({ open, onClose, title, description, children, footer, size =
|
|
|
1073
2795
|
}
|
|
1074
2796
|
|
|
1075
2797
|
// src/components/Textarea/Textarea.tsx
|
|
1076
|
-
import * as
|
|
1077
|
-
import { jsx as
|
|
1078
|
-
var Textarea =
|
|
1079
|
-
({ className,
|
|
2798
|
+
import * as React17 from "react";
|
|
2799
|
+
import { jsx as jsx33, jsxs as jsxs27 } from "react/jsx-runtime";
|
|
2800
|
+
var Textarea = React17.forwardRef(
|
|
2801
|
+
({ className, fieldLabel, textStyle = "source", id, placeholder, ...props }, ref) => {
|
|
2802
|
+
const generatedId = React17.useId();
|
|
2803
|
+
const fieldId = id ?? generatedId;
|
|
2804
|
+
const input = /* @__PURE__ */ jsx33(
|
|
2805
|
+
"textarea",
|
|
2806
|
+
{
|
|
2807
|
+
ref,
|
|
2808
|
+
id: fieldLabel ? fieldId : id,
|
|
2809
|
+
placeholder: fieldLabel ? placeholder || " " : placeholder,
|
|
2810
|
+
className: cn("fractal-textarea", className),
|
|
2811
|
+
"data-text-style": textStyle,
|
|
2812
|
+
...props
|
|
2813
|
+
}
|
|
2814
|
+
);
|
|
2815
|
+
return fieldLabel ? /* @__PURE__ */ jsxs27("div", { className: "fractal-floating-field fractal-floating-field--textarea", "data-control-size": "md", children: [
|
|
2816
|
+
input,
|
|
2817
|
+
/* @__PURE__ */ jsx33(FloatingFieldBorder, { label: fieldLabel ?? "" }),
|
|
2818
|
+
/* @__PURE__ */ jsx33("label", { className: "fractal-floating-field__label", htmlFor: fieldId, children: fieldLabel })
|
|
2819
|
+
] }) : input;
|
|
2820
|
+
}
|
|
1080
2821
|
);
|
|
1081
2822
|
Textarea.displayName = "Textarea";
|
|
1082
2823
|
|
|
2824
|
+
// src/components/TextButton/TextButton.tsx
|
|
2825
|
+
import * as React18 from "react";
|
|
2826
|
+
import { jsx as jsx34, jsxs as jsxs28 } from "react/jsx-runtime";
|
|
2827
|
+
var TextButton = React18.forwardRef(
|
|
2828
|
+
({ className, icon, iconPosition = "start", size = "md", tone = "primary", children, ...props }, ref) => /* @__PURE__ */ jsxs28(
|
|
2829
|
+
"button",
|
|
2830
|
+
{
|
|
2831
|
+
ref,
|
|
2832
|
+
className: cn("fractal-text-button", `fractal-text-button--${size}`, `fractal-text-button--${tone}`, className),
|
|
2833
|
+
type: "button",
|
|
2834
|
+
...props,
|
|
2835
|
+
children: [
|
|
2836
|
+
icon && iconPosition === "start" && /* @__PURE__ */ jsx34("span", { className: "fractal-text-button__icon", "aria-hidden": "true", children: icon }),
|
|
2837
|
+
/* @__PURE__ */ jsx34("span", { children }),
|
|
2838
|
+
icon && iconPosition === "end" && /* @__PURE__ */ jsx34("span", { className: "fractal-text-button__icon", "aria-hidden": "true", children: icon })
|
|
2839
|
+
]
|
|
2840
|
+
}
|
|
2841
|
+
)
|
|
2842
|
+
);
|
|
2843
|
+
TextButton.displayName = "TextButton";
|
|
2844
|
+
|
|
1083
2845
|
// src/components/FileDropzone/FileDropzone.tsx
|
|
1084
|
-
import * as
|
|
1085
|
-
import { Close as
|
|
1086
|
-
import { jsx as
|
|
2846
|
+
import * as React19 from "react";
|
|
2847
|
+
import { Close as Close4, FileArrowUp } from "@mirror-physics/fractal-icons";
|
|
2848
|
+
import { jsx as jsx35, jsxs as jsxs29 } from "react/jsx-runtime";
|
|
1087
2849
|
function FileDropzone({
|
|
1088
2850
|
files,
|
|
1089
2851
|
onFilesChange,
|
|
@@ -1094,17 +2856,17 @@ function FileDropzone({
|
|
|
1094
2856
|
description = "Files stay attached to this record.",
|
|
1095
2857
|
className
|
|
1096
2858
|
}) {
|
|
1097
|
-
const inputId =
|
|
1098
|
-
const inputRef =
|
|
1099
|
-
const [isDragging, setIsDragging] =
|
|
2859
|
+
const inputId = React19.useId();
|
|
2860
|
+
const inputRef = React19.useRef(null);
|
|
2861
|
+
const [isDragging, setIsDragging] = React19.useState(false);
|
|
1100
2862
|
const addFiles = (nextFiles) => {
|
|
1101
2863
|
if (disabled) return;
|
|
1102
2864
|
const additions = Array.from(nextFiles);
|
|
1103
2865
|
if (additions.length === 0) return;
|
|
1104
2866
|
onFilesChange(multiple ? [...files, ...additions] : additions.slice(0, 1));
|
|
1105
2867
|
};
|
|
1106
|
-
return /* @__PURE__ */
|
|
1107
|
-
/* @__PURE__ */
|
|
2868
|
+
return /* @__PURE__ */ jsxs29("div", { className: cn("fractal-file-dropzone", className), children: [
|
|
2869
|
+
/* @__PURE__ */ jsx35(
|
|
1108
2870
|
"input",
|
|
1109
2871
|
{
|
|
1110
2872
|
ref: inputRef,
|
|
@@ -1120,7 +2882,7 @@ function FileDropzone({
|
|
|
1120
2882
|
}
|
|
1121
2883
|
}
|
|
1122
2884
|
),
|
|
1123
|
-
/* @__PURE__ */
|
|
2885
|
+
/* @__PURE__ */ jsxs29(
|
|
1124
2886
|
"button",
|
|
1125
2887
|
{
|
|
1126
2888
|
className: "fractal-file-dropzone__target",
|
|
@@ -1143,18 +2905,18 @@ function FileDropzone({
|
|
|
1143
2905
|
addFiles(event.dataTransfer.files);
|
|
1144
2906
|
},
|
|
1145
2907
|
children: [
|
|
1146
|
-
/* @__PURE__ */
|
|
1147
|
-
/* @__PURE__ */
|
|
1148
|
-
/* @__PURE__ */
|
|
1149
|
-
description && /* @__PURE__ */
|
|
2908
|
+
/* @__PURE__ */ jsx35(FileArrowUp, { "aria-hidden": "true", size: 20 }),
|
|
2909
|
+
/* @__PURE__ */ jsxs29("span", { className: "fractal-file-dropzone__copy", children: [
|
|
2910
|
+
/* @__PURE__ */ jsx35("span", { className: "fractal-file-dropzone__title", children: title }),
|
|
2911
|
+
description && /* @__PURE__ */ jsx35("span", { className: "fractal-file-dropzone__description", children: description })
|
|
1150
2912
|
] })
|
|
1151
2913
|
]
|
|
1152
2914
|
}
|
|
1153
2915
|
),
|
|
1154
|
-
files.length > 0 && /* @__PURE__ */
|
|
1155
|
-
/* @__PURE__ */
|
|
1156
|
-
/* @__PURE__ */
|
|
1157
|
-
/* @__PURE__ */
|
|
2916
|
+
files.length > 0 && /* @__PURE__ */ jsx35("ul", { className: "fractal-file-dropzone__files", "aria-label": "Attached files", children: files.map((file, index) => /* @__PURE__ */ jsxs29("li", { className: "fractal-file-dropzone__file", children: [
|
|
2917
|
+
/* @__PURE__ */ jsx35("span", { className: "fractal-file-dropzone__file-name", children: file.name }),
|
|
2918
|
+
/* @__PURE__ */ jsx35("span", { className: "fractal-file-dropzone__file-meta", children: formatFileSize(file.size) }),
|
|
2919
|
+
/* @__PURE__ */ jsx35(
|
|
1158
2920
|
"button",
|
|
1159
2921
|
{
|
|
1160
2922
|
className: "fractal-file-dropzone__remove",
|
|
@@ -1162,7 +2924,7 @@ function FileDropzone({
|
|
|
1162
2924
|
"aria-label": `Remove ${file.name}`,
|
|
1163
2925
|
disabled,
|
|
1164
2926
|
onClick: () => onFilesChange(files.filter((_, fileIndex) => fileIndex !== index)),
|
|
1165
|
-
children: /* @__PURE__ */
|
|
2927
|
+
children: /* @__PURE__ */ jsx35(Close4, { "aria-hidden": "true", size: 14 })
|
|
1166
2928
|
}
|
|
1167
2929
|
)
|
|
1168
2930
|
] }, `${file.name}-${file.size}-${index}`)) })
|
|
@@ -1173,42 +2935,189 @@ function formatFileSize(bytes) {
|
|
|
1173
2935
|
if (bytes < 1024 * 1024) return `${Math.round(bytes / 1024)} KB`;
|
|
1174
2936
|
return `${(bytes / (1024 * 1024)).toFixed(1)} MB`;
|
|
1175
2937
|
}
|
|
2938
|
+
|
|
2939
|
+
// src/components/Pagination/Pagination.tsx
|
|
2940
|
+
import { ArrowLeft, ArrowRight } from "@mirror-physics/fractal-icons";
|
|
2941
|
+
import { jsx as jsx36, jsxs as jsxs30 } from "react/jsx-runtime";
|
|
2942
|
+
function Pagination({
|
|
2943
|
+
page,
|
|
2944
|
+
pageSize,
|
|
2945
|
+
totalItems,
|
|
2946
|
+
onPageChange,
|
|
2947
|
+
pageSizeOptions,
|
|
2948
|
+
onPageSizeChange,
|
|
2949
|
+
ariaLabel = "Pagination",
|
|
2950
|
+
className
|
|
2951
|
+
}) {
|
|
2952
|
+
const totalPages = Math.max(1, Math.ceil(totalItems / pageSize));
|
|
2953
|
+
const currentPage = Math.min(Math.max(page, 1), totalPages);
|
|
2954
|
+
const start = totalItems === 0 ? 0 : (currentPage - 1) * pageSize + 1;
|
|
2955
|
+
const end = Math.min(currentPage * pageSize, totalItems);
|
|
2956
|
+
const canChangePageSize = pageSizeOptions != null && pageSizeOptions.length > 0 && onPageSizeChange != null;
|
|
2957
|
+
return /* @__PURE__ */ jsxs30("nav", { className: cn("fractal-pagination", className), "aria-label": ariaLabel, children: [
|
|
2958
|
+
/* @__PURE__ */ jsx36("span", { className: "fractal-pagination__summary", children: totalItems === 0 ? "No results" : `${start}-${end} of ${totalItems}` }),
|
|
2959
|
+
/* @__PURE__ */ jsxs30("div", { className: "fractal-pagination__controls", children: [
|
|
2960
|
+
canChangePageSize && /* @__PURE__ */ jsx36(
|
|
2961
|
+
Dropdown,
|
|
2962
|
+
{
|
|
2963
|
+
align: "right",
|
|
2964
|
+
className: "fractal-pagination__page-size",
|
|
2965
|
+
direction: "up",
|
|
2966
|
+
items: pageSizeOptions.map((option) => ({
|
|
2967
|
+
value: String(option),
|
|
2968
|
+
description: `${option} per page`
|
|
2969
|
+
})),
|
|
2970
|
+
onSelect: (value) => onPageSizeChange(Number(value)),
|
|
2971
|
+
selectedValue: String(pageSize),
|
|
2972
|
+
size: "sm",
|
|
2973
|
+
triggerLabel: "Results per page",
|
|
2974
|
+
triggerVariant: "tertiary"
|
|
2975
|
+
}
|
|
2976
|
+
),
|
|
2977
|
+
/* @__PURE__ */ jsx36(
|
|
2978
|
+
"button",
|
|
2979
|
+
{
|
|
2980
|
+
className: "fractal-pagination__button",
|
|
2981
|
+
type: "button",
|
|
2982
|
+
"aria-label": "Previous page",
|
|
2983
|
+
title: "Previous page",
|
|
2984
|
+
disabled: currentPage === 1 || totalItems === 0,
|
|
2985
|
+
onClick: () => onPageChange(currentPage - 1),
|
|
2986
|
+
children: /* @__PURE__ */ jsx36(ArrowLeft, { "aria-hidden": "true", size: 16 })
|
|
2987
|
+
}
|
|
2988
|
+
),
|
|
2989
|
+
/* @__PURE__ */ jsxs30("span", { className: "fractal-pagination__page", "aria-current": "page", children: [
|
|
2990
|
+
currentPage,
|
|
2991
|
+
" of ",
|
|
2992
|
+
totalPages
|
|
2993
|
+
] }),
|
|
2994
|
+
/* @__PURE__ */ jsx36(
|
|
2995
|
+
"button",
|
|
2996
|
+
{
|
|
2997
|
+
className: "fractal-pagination__button",
|
|
2998
|
+
type: "button",
|
|
2999
|
+
"aria-label": "Next page",
|
|
3000
|
+
title: "Next page",
|
|
3001
|
+
disabled: currentPage === totalPages || totalItems === 0,
|
|
3002
|
+
onClick: () => onPageChange(currentPage + 1),
|
|
3003
|
+
children: /* @__PURE__ */ jsx36(ArrowRight, { "aria-hidden": "true", size: 16 })
|
|
3004
|
+
}
|
|
3005
|
+
)
|
|
3006
|
+
] })
|
|
3007
|
+
] });
|
|
3008
|
+
}
|
|
3009
|
+
|
|
3010
|
+
// src/components/Tooltip/Tooltip.tsx
|
|
3011
|
+
import * as TooltipPrimitive from "@radix-ui/react-tooltip";
|
|
3012
|
+
import { jsx as jsx37, jsxs as jsxs31 } from "react/jsx-runtime";
|
|
3013
|
+
function Tooltip({
|
|
3014
|
+
content,
|
|
3015
|
+
children,
|
|
3016
|
+
placement = "bottom",
|
|
3017
|
+
maxWidth = 320,
|
|
3018
|
+
delay = 0,
|
|
3019
|
+
disabled = false,
|
|
3020
|
+
className
|
|
3021
|
+
}) {
|
|
3022
|
+
if (disabled || content == null || content === "") return children;
|
|
3023
|
+
return /* @__PURE__ */ jsx37(TooltipPrimitive.Provider, { delayDuration: delay, children: /* @__PURE__ */ jsxs31(TooltipPrimitive.Root, { children: [
|
|
3024
|
+
/* @__PURE__ */ jsx37(TooltipPrimitive.Trigger, { asChild: true, children }),
|
|
3025
|
+
/* @__PURE__ */ jsx37(TooltipPrimitive.Portal, { children: /* @__PURE__ */ jsxs31(
|
|
3026
|
+
TooltipPrimitive.Content,
|
|
3027
|
+
{
|
|
3028
|
+
side: placement,
|
|
3029
|
+
sideOffset: 8,
|
|
3030
|
+
collisionPadding: 8,
|
|
3031
|
+
className: cn("fractal-tooltip", className),
|
|
3032
|
+
style: { "--tooltip-max-width": typeof maxWidth === "number" ? `${maxWidth}px` : maxWidth },
|
|
3033
|
+
children: [
|
|
3034
|
+
content,
|
|
3035
|
+
/* @__PURE__ */ jsx37(TooltipPrimitive.Arrow, { className: "fractal-tooltip-arrow", width: 8, height: 4, "aria-hidden": "true" })
|
|
3036
|
+
]
|
|
3037
|
+
}
|
|
3038
|
+
) })
|
|
3039
|
+
] }) });
|
|
3040
|
+
}
|
|
1176
3041
|
export {
|
|
1177
3042
|
Alert,
|
|
1178
3043
|
AlertDescription,
|
|
3044
|
+
AlertGhost,
|
|
1179
3045
|
AlertTitle,
|
|
3046
|
+
Breadcrumbs,
|
|
1180
3047
|
Button,
|
|
3048
|
+
ButtonGhost,
|
|
1181
3049
|
Card,
|
|
1182
3050
|
CardContent,
|
|
1183
3051
|
CardDescription,
|
|
1184
3052
|
CardFooter,
|
|
3053
|
+
CardGhost,
|
|
1185
3054
|
CardHeader,
|
|
1186
3055
|
CardTitle,
|
|
3056
|
+
Checkbox,
|
|
3057
|
+
CheckboxGhost,
|
|
1187
3058
|
Chip,
|
|
3059
|
+
ChipGhost,
|
|
3060
|
+
CodeBlock,
|
|
3061
|
+
ColumnEditor,
|
|
3062
|
+
ContentSwitcher,
|
|
3063
|
+
ContentSwitcherGhost,
|
|
3064
|
+
ConversationGhost,
|
|
1188
3065
|
DataTable,
|
|
3066
|
+
DataTableGhost,
|
|
1189
3067
|
Disclosure,
|
|
3068
|
+
DisclosureGhost,
|
|
1190
3069
|
Dropdown,
|
|
3070
|
+
DropdownGhost,
|
|
1191
3071
|
FeatureCard,
|
|
1192
3072
|
FileDropzone,
|
|
3073
|
+
FileDropzoneGhost,
|
|
1193
3074
|
FolderCard,
|
|
3075
|
+
Ghost,
|
|
3076
|
+
GhostLine,
|
|
1194
3077
|
Input,
|
|
3078
|
+
InputGhost,
|
|
1195
3079
|
Label,
|
|
3080
|
+
LabelGhost,
|
|
3081
|
+
LatticeLoader,
|
|
1196
3082
|
Link,
|
|
3083
|
+
LinkGhost,
|
|
1197
3084
|
Modal,
|
|
3085
|
+
ModalGhost,
|
|
3086
|
+
NumberInput,
|
|
3087
|
+
Pagination,
|
|
3088
|
+
PaginationGhost,
|
|
3089
|
+
PasswordInput,
|
|
1198
3090
|
PromptCard,
|
|
3091
|
+
PromptCardGhost,
|
|
1199
3092
|
PromptGrid,
|
|
3093
|
+
Radio,
|
|
1200
3094
|
SidePanel,
|
|
3095
|
+
SidePanelGhost,
|
|
1201
3096
|
Sidebar,
|
|
3097
|
+
SidebarAccountMenu,
|
|
1202
3098
|
SidebarBrand,
|
|
1203
3099
|
SidebarFooter,
|
|
3100
|
+
SidebarGhost,
|
|
1204
3101
|
SidebarHeader,
|
|
1205
3102
|
SidebarNav,
|
|
1206
3103
|
SidebarNavItem,
|
|
1207
3104
|
SidebarSection,
|
|
3105
|
+
Slider,
|
|
1208
3106
|
SortableTable,
|
|
3107
|
+
SortableTableGhost,
|
|
3108
|
+
TableSearch,
|
|
1209
3109
|
Tabs,
|
|
3110
|
+
TabsGhost,
|
|
3111
|
+
TextButton,
|
|
3112
|
+
TextButtonGhost,
|
|
1210
3113
|
Textarea,
|
|
3114
|
+
TextareaGhost,
|
|
3115
|
+
Toast,
|
|
3116
|
+
ToastViewport,
|
|
1211
3117
|
Toggle,
|
|
3118
|
+
ToggleGhost,
|
|
3119
|
+
Tooltip,
|
|
3120
|
+
UILoader,
|
|
1212
3121
|
cn,
|
|
1213
3122
|
useEscapeDismiss
|
|
1214
3123
|
};
|