@mirror-physics/fractal-ui 0.2.0-next.7 → 0.2.0-next.70
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/dist/index.cjs +1683 -288
- package/dist/index.cjs.map +1 -1
- package/dist/index.css +1472 -88
- package/dist/index.css.map +1 -1
- package/dist/index.d.cts +318 -11
- package/dist/index.d.ts +318 -11
- package/dist/index.js +1647 -285
- package/dist/index.js.map +1 -1
- package/dist/lattice-FAYE5KWW.svg +3 -0
- package/dist/tokens.css +5 -3
- package/package.json +7 -1
package/dist/index.js
CHANGED
|
@@ -165,44 +165,415 @@ var Button = React.forwardRef(
|
|
|
165
165
|
);
|
|
166
166
|
Button.displayName = "Button";
|
|
167
167
|
|
|
168
|
+
// src/components/CodeBlock/CodeBlock.tsx
|
|
169
|
+
import { useEffect, useMemo, useRef, useState as useState2 } from "react";
|
|
170
|
+
import CodeMirror from "@uiw/react-codemirror";
|
|
171
|
+
import { HighlightStyle, foldGutter, foldService, syntaxHighlighting } from "@codemirror/language";
|
|
172
|
+
import { json } from "@codemirror/lang-json";
|
|
173
|
+
import {
|
|
174
|
+
Decoration,
|
|
175
|
+
EditorView,
|
|
176
|
+
MatchDecorator,
|
|
177
|
+
ViewPlugin,
|
|
178
|
+
lineNumbers as lineNumberGutter
|
|
179
|
+
} from "@codemirror/view";
|
|
180
|
+
import { tags } from "@lezer/highlight";
|
|
181
|
+
import { Check, Copy } from "@mirror-physics/fractal-icons";
|
|
182
|
+
import { jsx, jsxs as jsxs2 } from "react/jsx-runtime";
|
|
183
|
+
var codeTheme = EditorView.theme({
|
|
184
|
+
"&": {
|
|
185
|
+
backgroundColor: "transparent",
|
|
186
|
+
color: "var(--fg-primary)",
|
|
187
|
+
fontSize: "0.75rem"
|
|
188
|
+
},
|
|
189
|
+
"&.cm-focused": { outline: "none" },
|
|
190
|
+
".cm-scroller": {
|
|
191
|
+
fontFamily: "var(--font-mono)",
|
|
192
|
+
lineHeight: "1.55",
|
|
193
|
+
overscrollBehavior: "none"
|
|
194
|
+
},
|
|
195
|
+
".cm-content": { padding: "10px 0" },
|
|
196
|
+
".cm-line": {
|
|
197
|
+
padding: "0 12px 0 calc(12px + var(--fractal-code-wrap-indent, 0ch))",
|
|
198
|
+
textIndent: "calc(0px - var(--fractal-code-wrap-indent, 0ch))"
|
|
199
|
+
},
|
|
200
|
+
".cm-cursor, .cm-dropCursor": { borderLeftColor: "var(--fg-primary)" },
|
|
201
|
+
".cm-gutters": {
|
|
202
|
+
backgroundColor: "var(--bg-canvas)",
|
|
203
|
+
borderRight: "1px solid var(--border-subtle)",
|
|
204
|
+
color: "var(--fg-tertiary)"
|
|
205
|
+
},
|
|
206
|
+
".cm-lineNumbers .cm-gutterElement": { padding: "0 10px 0 4px" },
|
|
207
|
+
".cm-foldGutter": { width: "14px" },
|
|
208
|
+
".cm-foldGutter .cm-gutterElement": {
|
|
209
|
+
position: "relative",
|
|
210
|
+
display: "block",
|
|
211
|
+
width: "14px",
|
|
212
|
+
padding: "0"
|
|
213
|
+
},
|
|
214
|
+
".cm-foldGutter .cm-gutterElement > span": {
|
|
215
|
+
position: "absolute",
|
|
216
|
+
top: "2px",
|
|
217
|
+
left: "0",
|
|
218
|
+
display: "inline-flex",
|
|
219
|
+
width: "14px",
|
|
220
|
+
height: "14px",
|
|
221
|
+
alignItems: "center",
|
|
222
|
+
justifyContent: "center",
|
|
223
|
+
padding: "0",
|
|
224
|
+
color: "var(--fg-tertiary)",
|
|
225
|
+
lineHeight: "14px",
|
|
226
|
+
transition: "color 120ms ease"
|
|
227
|
+
},
|
|
228
|
+
'.cm-foldGutter .cm-gutterElement > span[title="Fold line"]': { transform: "translateY(-3px)" },
|
|
229
|
+
".cm-foldGutter .cm-gutterElement > span:hover": { color: "var(--fg-secondary)" },
|
|
230
|
+
".fractal-code-block__escape": { color: "var(--fg-secondary)" },
|
|
231
|
+
".cm-activeLine, .cm-activeLineGutter": { backgroundColor: "var(--bg-surface-1)" },
|
|
232
|
+
".cm-selectionBackground, &.cm-focused .cm-selectionBackground, ::selection": {
|
|
233
|
+
backgroundColor: "var(--accent-surface-stroke) !important"
|
|
234
|
+
},
|
|
235
|
+
".cm-searchMatch": {
|
|
236
|
+
backgroundColor: "var(--warning-surface)",
|
|
237
|
+
outline: "1px solid var(--warning-surface-stroke)"
|
|
238
|
+
},
|
|
239
|
+
".cm-searchMatch.cm-searchMatch-selected": { backgroundColor: "var(--warning-subtle)" },
|
|
240
|
+
".cm-panels": { backgroundColor: "var(--bg-surface-1)", color: "var(--fg-primary)" },
|
|
241
|
+
".cm-tooltip": {
|
|
242
|
+
borderColor: "var(--border-subtle)",
|
|
243
|
+
backgroundColor: "var(--bg-canvas)",
|
|
244
|
+
color: "var(--fg-primary)"
|
|
245
|
+
}
|
|
246
|
+
});
|
|
247
|
+
var fractalHighlightStyle = HighlightStyle.define([
|
|
248
|
+
{ tag: tags.comment, color: "var(--fg-tertiary)", fontStyle: "italic" },
|
|
249
|
+
{ tag: [tags.keyword, tags.controlKeyword, tags.operatorKeyword], color: "var(--purple-default)" },
|
|
250
|
+
{ tag: [tags.string, tags.special(tags.string)], color: "var(--purple-default)" },
|
|
251
|
+
{ tag: [tags.number, tags.bool, tags.null], color: "var(--orange-default)" },
|
|
252
|
+
{ tag: [tags.function(tags.variableName), tags.labelName], color: "var(--accent-default)" },
|
|
253
|
+
{ tag: [tags.typeName, tags.className, tags.namespace], color: "var(--pink-default)" },
|
|
254
|
+
{ tag: [tags.propertyName, tags.attributeName], color: "var(--success-default)" },
|
|
255
|
+
{ tag: [tags.operator, tags.punctuation], color: "var(--fg-secondary)" },
|
|
256
|
+
{ tag: tags.bracket, color: "var(--accent-default)" },
|
|
257
|
+
{ tag: [tags.heading, tags.strong], color: "var(--fg-primary)", fontWeight: "600" },
|
|
258
|
+
{ tag: tags.emphasis, fontStyle: "italic" },
|
|
259
|
+
{ tag: tags.link, color: "var(--accent-default)", textDecoration: "underline" },
|
|
260
|
+
{ tag: tags.invalid, color: "var(--error-default)", textDecoration: "underline wavy" }
|
|
261
|
+
]);
|
|
262
|
+
var jsonSupport = json();
|
|
263
|
+
var JSON_LANGUAGE_NAMES = /* @__PURE__ */ new Set(["json", "jsonl", "ndjson", "geojson"]);
|
|
264
|
+
var JSON_LINES_LANGUAGE_NAMES = /* @__PURE__ */ new Set(["jsonl", "ndjson"]);
|
|
265
|
+
var JSON_LINES_PRETTY_PRINT_THRESHOLD = 160;
|
|
266
|
+
var JSON_PROPERTY_PREFIX = /^(\s*"(?:\\.|[^"\\])*"\s*:\s*)/;
|
|
267
|
+
function countVisualColumns(value) {
|
|
268
|
+
let columns = 0;
|
|
269
|
+
for (const character of value) columns += character === " " ? 2 : 1;
|
|
270
|
+
return columns;
|
|
271
|
+
}
|
|
272
|
+
function getWrappedLineIndent(line) {
|
|
273
|
+
const leadingWhitespace = line.match(/^\s*/)?.[0] ?? "";
|
|
274
|
+
if (JSON_PROPERTY_PREFIX.test(line)) return Math.min(countVisualColumns(leadingWhitespace), 24);
|
|
275
|
+
return Math.min(countVisualColumns(leadingWhitespace) + 2, 12);
|
|
276
|
+
}
|
|
277
|
+
function buildWrappedLineIndentation(view) {
|
|
278
|
+
const decorations = [];
|
|
279
|
+
const decoratedLines = /* @__PURE__ */ new Set();
|
|
280
|
+
for (const visibleRange of view.visibleRanges) {
|
|
281
|
+
let position = visibleRange.from;
|
|
282
|
+
while (position <= visibleRange.to) {
|
|
283
|
+
const line = view.state.doc.lineAt(position);
|
|
284
|
+
if (!decoratedLines.has(line.from)) {
|
|
285
|
+
const indent = getWrappedLineIndent(line.text);
|
|
286
|
+
decorations.push(Decoration.line({
|
|
287
|
+
attributes: { style: `--fractal-code-wrap-indent: ${indent}ch` }
|
|
288
|
+
}).range(line.from));
|
|
289
|
+
decoratedLines.add(line.from);
|
|
290
|
+
}
|
|
291
|
+
if (line.to >= visibleRange.to) break;
|
|
292
|
+
position = line.to + 1;
|
|
293
|
+
}
|
|
294
|
+
}
|
|
295
|
+
return Decoration.set(decorations, true);
|
|
296
|
+
}
|
|
297
|
+
var wrappedLineIndentation = ViewPlugin.fromClass(class {
|
|
298
|
+
constructor(view) {
|
|
299
|
+
this.decorations = buildWrappedLineIndentation(view);
|
|
300
|
+
}
|
|
301
|
+
update(update) {
|
|
302
|
+
this.decorations = buildWrappedLineIndentation(update.view);
|
|
303
|
+
}
|
|
304
|
+
}, {
|
|
305
|
+
decorations: (plugin) => plugin.decorations
|
|
306
|
+
});
|
|
307
|
+
var jsonEscapeMatcher = new MatchDecorator({
|
|
308
|
+
regexp: /\\(?:["\\/bfnrt]|u[0-9a-fA-F]{4})/g,
|
|
309
|
+
decoration: Decoration.mark({ class: "fractal-code-block__escape" })
|
|
310
|
+
});
|
|
311
|
+
var jsonEscapeHighlighting = ViewPlugin.fromClass(class {
|
|
312
|
+
constructor(view) {
|
|
313
|
+
this.decorations = jsonEscapeMatcher.createDeco(view);
|
|
314
|
+
}
|
|
315
|
+
update(update) {
|
|
316
|
+
this.decorations = jsonEscapeMatcher.updateDeco(update, this.decorations);
|
|
317
|
+
}
|
|
318
|
+
}, {
|
|
319
|
+
decorations: (plugin) => plugin.decorations
|
|
320
|
+
});
|
|
321
|
+
function formatJsonLinesForDisplay(value) {
|
|
322
|
+
return value.split(/\r?\n/).map((line) => {
|
|
323
|
+
const firstContentIndex = line.search(/\S/);
|
|
324
|
+
if (firstContentIndex < 0 || line.length - firstContentIndex <= JSON_LINES_PRETTY_PRINT_THRESHOLD) return line;
|
|
325
|
+
const indentation = line.slice(0, firstContentIndex);
|
|
326
|
+
try {
|
|
327
|
+
const parsed = JSON.parse(line.slice(firstContentIndex));
|
|
328
|
+
if (parsed === null || typeof parsed !== "object") return line;
|
|
329
|
+
return JSON.stringify(parsed, null, 2).split("\n").map((formattedLine) => `${indentation}${formattedLine}`).join("\n");
|
|
330
|
+
} catch {
|
|
331
|
+
return line;
|
|
332
|
+
}
|
|
333
|
+
}).join("\n");
|
|
334
|
+
}
|
|
335
|
+
function findJsonContainerEnd(document2, start) {
|
|
336
|
+
const openingCharacter = document2[start];
|
|
337
|
+
if (openingCharacter !== "{" && openingCharacter !== "[") return null;
|
|
338
|
+
const closingCharacters = [];
|
|
339
|
+
let isInsideString = false;
|
|
340
|
+
let isEscaped = false;
|
|
341
|
+
for (let index = start; index < document2.length; index += 1) {
|
|
342
|
+
const character = document2[index];
|
|
343
|
+
if (isInsideString) {
|
|
344
|
+
if (isEscaped) {
|
|
345
|
+
isEscaped = false;
|
|
346
|
+
} else if (character === "\\") {
|
|
347
|
+
isEscaped = true;
|
|
348
|
+
} else if (character === '"') {
|
|
349
|
+
isInsideString = false;
|
|
350
|
+
}
|
|
351
|
+
continue;
|
|
352
|
+
}
|
|
353
|
+
if (character === '"') {
|
|
354
|
+
isInsideString = true;
|
|
355
|
+
} else if (character === "{") {
|
|
356
|
+
closingCharacters.push("}");
|
|
357
|
+
} else if (character === "[") {
|
|
358
|
+
closingCharacters.push("]");
|
|
359
|
+
} else if (character === "}" || character === "]") {
|
|
360
|
+
if (closingCharacters.pop() !== character) return null;
|
|
361
|
+
if (closingCharacters.length === 0) return index;
|
|
362
|
+
}
|
|
363
|
+
}
|
|
364
|
+
return null;
|
|
365
|
+
}
|
|
366
|
+
var jsonLinesFoldSupport = foldService.of((state, lineStart, lineEnd) => {
|
|
367
|
+
const line = state.doc.sliceString(lineStart, lineEnd);
|
|
368
|
+
const firstContentIndex = line.search(/\S/);
|
|
369
|
+
if (firstContentIndex < 0) return null;
|
|
370
|
+
const containerStart = lineStart + firstContentIndex;
|
|
371
|
+
const openingCharacter = line[firstContentIndex];
|
|
372
|
+
if (openingCharacter !== "{" && openingCharacter !== "[") return null;
|
|
373
|
+
const document2 = state.doc.toString();
|
|
374
|
+
const containerEnd = findJsonContainerEnd(document2, containerStart);
|
|
375
|
+
if (containerEnd === null || containerEnd - containerStart < 2) return null;
|
|
376
|
+
try {
|
|
377
|
+
const parsed = JSON.parse(document2.slice(containerStart, containerEnd + 1));
|
|
378
|
+
if (parsed === null || typeof parsed !== "object") return null;
|
|
379
|
+
} catch {
|
|
380
|
+
return null;
|
|
381
|
+
}
|
|
382
|
+
return {
|
|
383
|
+
from: containerStart + 1,
|
|
384
|
+
to: containerEnd
|
|
385
|
+
};
|
|
386
|
+
});
|
|
387
|
+
function resolveLanguage(language, fileName) {
|
|
388
|
+
const normalized = language?.trim().toLowerCase();
|
|
389
|
+
const extension = fileName?.split(/[?#]/, 1)[0].split(".").pop()?.toLowerCase();
|
|
390
|
+
if (normalized && JSON_LANGUAGE_NAMES.has(normalized) || extension && JSON_LANGUAGE_NAMES.has(extension)) {
|
|
391
|
+
const isJsonLines = Boolean(
|
|
392
|
+
normalized && JSON_LINES_LANGUAGE_NAMES.has(normalized) || extension && JSON_LINES_LANGUAGE_NAMES.has(extension)
|
|
393
|
+
);
|
|
394
|
+
return { label: isJsonLines ? "JSONL" : "JSON", support: jsonSupport, isJsonLines };
|
|
395
|
+
}
|
|
396
|
+
if (normalized && !["text", "txt", "plaintext", "plain"].includes(normalized)) {
|
|
397
|
+
return { label: language?.trim(), support: null, isJsonLines: false };
|
|
398
|
+
}
|
|
399
|
+
return { support: null, isJsonLines: false };
|
|
400
|
+
}
|
|
401
|
+
function CodeBlock({
|
|
402
|
+
value,
|
|
403
|
+
language,
|
|
404
|
+
fileName,
|
|
405
|
+
label,
|
|
406
|
+
editable = false,
|
|
407
|
+
onChange,
|
|
408
|
+
lineNumbers = true,
|
|
409
|
+
wrap = true,
|
|
410
|
+
copyable = true,
|
|
411
|
+
ariaLabel,
|
|
412
|
+
height,
|
|
413
|
+
minHeight,
|
|
414
|
+
maxHeight = "28rem",
|
|
415
|
+
placeholder,
|
|
416
|
+
autoFocus,
|
|
417
|
+
className,
|
|
418
|
+
...props
|
|
419
|
+
}) {
|
|
420
|
+
const resolvedLanguage = useMemo(() => resolveLanguage(language, fileName), [fileName, language]);
|
|
421
|
+
const displayValue = useMemo(
|
|
422
|
+
() => !editable && resolvedLanguage.isJsonLines ? formatJsonLinesForDisplay(value) : value,
|
|
423
|
+
[editable, resolvedLanguage.isJsonLines, value]
|
|
424
|
+
);
|
|
425
|
+
const [copyStatus, setCopyStatus] = useState2("idle");
|
|
426
|
+
const copyResetTimer = useRef(null);
|
|
427
|
+
useEffect(() => () => {
|
|
428
|
+
if (copyResetTimer.current) clearTimeout(copyResetTimer.current);
|
|
429
|
+
}, []);
|
|
430
|
+
const extensions = useMemo(() => [
|
|
431
|
+
codeTheme,
|
|
432
|
+
syntaxHighlighting(fractalHighlightStyle),
|
|
433
|
+
...resolvedLanguage.support ? [resolvedLanguage.support] : [],
|
|
434
|
+
...resolvedLanguage.support ? [jsonEscapeHighlighting] : [],
|
|
435
|
+
...resolvedLanguage.isJsonLines ? [jsonLinesFoldSupport] : [],
|
|
436
|
+
...lineNumbers ? [foldGutter(), lineNumberGutter()] : [],
|
|
437
|
+
...wrap ? [EditorView.lineWrapping, wrappedLineIndentation] : []
|
|
438
|
+
], [lineNumbers, resolvedLanguage.isJsonLines, resolvedLanguage.support, wrap]);
|
|
439
|
+
const languageLabel = resolvedLanguage.label;
|
|
440
|
+
const toolbarLabel = label ?? fileName ?? languageLabel;
|
|
441
|
+
const surfaceLabel = ariaLabel ?? (fileName ? `${fileName} ${editable ? "editor" : "viewer"}` : `Code ${editable ? "editor" : "viewer"}`);
|
|
442
|
+
const copyCode = async () => {
|
|
443
|
+
try {
|
|
444
|
+
await navigator.clipboard.writeText(value);
|
|
445
|
+
setCopyStatus("copied");
|
|
446
|
+
} catch {
|
|
447
|
+
setCopyStatus("error");
|
|
448
|
+
}
|
|
449
|
+
if (copyResetTimer.current) clearTimeout(copyResetTimer.current);
|
|
450
|
+
copyResetTimer.current = setTimeout(() => setCopyStatus("idle"), 1800);
|
|
451
|
+
};
|
|
452
|
+
const showToolbar = toolbarLabel !== void 0 || copyable || editable;
|
|
453
|
+
return /* @__PURE__ */ jsxs2(
|
|
454
|
+
"div",
|
|
455
|
+
{
|
|
456
|
+
className: cn(
|
|
457
|
+
"fractal-code-block",
|
|
458
|
+
editable && "fractal-code-block--editable",
|
|
459
|
+
!lineNumbers && "fractal-code-block--no-line-numbers",
|
|
460
|
+
className
|
|
461
|
+
),
|
|
462
|
+
...props,
|
|
463
|
+
children: [
|
|
464
|
+
showToolbar && /* @__PURE__ */ jsxs2("div", { className: "fractal-code-block__toolbar", children: [
|
|
465
|
+
/* @__PURE__ */ jsxs2("div", { className: "fractal-code-block__identity", children: [
|
|
466
|
+
toolbarLabel !== void 0 && /* @__PURE__ */ jsx("span", { className: "fractal-code-block__label", title: typeof toolbarLabel === "string" ? toolbarLabel : void 0, children: toolbarLabel }),
|
|
467
|
+
fileName && languageLabel && /* @__PURE__ */ jsx("span", { className: "fractal-code-block__language", children: languageLabel }),
|
|
468
|
+
editable && /* @__PURE__ */ jsx("span", { className: "fractal-code-block__mode", children: "Editing" })
|
|
469
|
+
] }),
|
|
470
|
+
copyable && /* @__PURE__ */ jsxs2(
|
|
471
|
+
"button",
|
|
472
|
+
{
|
|
473
|
+
type: "button",
|
|
474
|
+
className: "fractal-code-block__copy",
|
|
475
|
+
"aria-label": copyStatus === "copied" ? "Code copied" : "Copy code",
|
|
476
|
+
onClick: () => void copyCode(),
|
|
477
|
+
children: [
|
|
478
|
+
copyStatus === "copied" ? /* @__PURE__ */ jsx(Check, { size: 14 }) : /* @__PURE__ */ jsx(Copy, { size: 14 }),
|
|
479
|
+
/* @__PURE__ */ jsx("span", { children: copyStatus === "copied" ? "Copied" : copyStatus === "error" ? "Copy failed" : "Copy" })
|
|
480
|
+
]
|
|
481
|
+
}
|
|
482
|
+
)
|
|
483
|
+
] }),
|
|
484
|
+
/* @__PURE__ */ jsx("div", { className: "fractal-code-block__surface", children: /* @__PURE__ */ jsx(
|
|
485
|
+
CodeMirror,
|
|
486
|
+
{
|
|
487
|
+
"aria-label": surfaceLabel,
|
|
488
|
+
value: displayValue,
|
|
489
|
+
editable,
|
|
490
|
+
readOnly: !editable,
|
|
491
|
+
onChange,
|
|
492
|
+
extensions,
|
|
493
|
+
theme: "none",
|
|
494
|
+
basicSetup: {
|
|
495
|
+
lineNumbers: false,
|
|
496
|
+
foldGutter: false,
|
|
497
|
+
drawSelection: editable,
|
|
498
|
+
highlightActiveLine: editable,
|
|
499
|
+
highlightActiveLineGutter: editable,
|
|
500
|
+
highlightSelectionMatches: editable,
|
|
501
|
+
autocompletion: editable,
|
|
502
|
+
history: editable
|
|
503
|
+
},
|
|
504
|
+
indentWithTab: editable,
|
|
505
|
+
height,
|
|
506
|
+
minHeight,
|
|
507
|
+
maxHeight,
|
|
508
|
+
placeholder,
|
|
509
|
+
autoFocus
|
|
510
|
+
}
|
|
511
|
+
) }),
|
|
512
|
+
/* @__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." : "" })
|
|
513
|
+
]
|
|
514
|
+
}
|
|
515
|
+
);
|
|
516
|
+
}
|
|
517
|
+
|
|
518
|
+
// src/components/Breadcrumbs/Breadcrumbs.tsx
|
|
519
|
+
import { ChevronRight } from "@mirror-physics/fractal-icons";
|
|
520
|
+
import { jsx as jsx2, jsxs as jsxs3 } from "react/jsx-runtime";
|
|
521
|
+
function Breadcrumbs({
|
|
522
|
+
items,
|
|
523
|
+
ariaLabel = "Breadcrumbs",
|
|
524
|
+
separator = /* @__PURE__ */ jsx2(ChevronRight, { "aria-hidden": "true", size: 14 }),
|
|
525
|
+
className,
|
|
526
|
+
...props
|
|
527
|
+
}) {
|
|
528
|
+
if (items.length === 0) return null;
|
|
529
|
+
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) => {
|
|
530
|
+
const isCurrent = index === items.length - 1;
|
|
531
|
+
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 });
|
|
532
|
+
return /* @__PURE__ */ jsxs3("li", { className: "fractal-breadcrumbs__item", children: [
|
|
533
|
+
index > 0 && /* @__PURE__ */ jsx2("span", { "aria-hidden": "true", className: "fractal-breadcrumbs__separator", children: separator }),
|
|
534
|
+
content
|
|
535
|
+
] }, index);
|
|
536
|
+
}) }) });
|
|
537
|
+
}
|
|
538
|
+
|
|
168
539
|
// src/components/Card/Card.tsx
|
|
169
540
|
import * as React2 from "react";
|
|
170
541
|
import { Folder as FolderIcon } from "@mirror-physics/fractal-icons";
|
|
171
|
-
import { jsx, jsxs as
|
|
542
|
+
import { jsx as jsx3, jsxs as jsxs4 } from "react/jsx-runtime";
|
|
172
543
|
var Card = React2.forwardRef(
|
|
173
|
-
({ className, ...props }, ref) => /* @__PURE__ */
|
|
544
|
+
({ className, ...props }, ref) => /* @__PURE__ */ jsx3("div", { ref, className: cn("fractal-card", className), ...props })
|
|
174
545
|
);
|
|
175
546
|
Card.displayName = "Card";
|
|
176
547
|
var CardHeader = React2.forwardRef(
|
|
177
|
-
({ className, ...props }, ref) => /* @__PURE__ */
|
|
548
|
+
({ className, ...props }, ref) => /* @__PURE__ */ jsx3("div", { ref, className: cn("fractal-card-header", className), ...props })
|
|
178
549
|
);
|
|
179
550
|
CardHeader.displayName = "CardHeader";
|
|
180
551
|
var CardTitle = React2.forwardRef(
|
|
181
|
-
({ className, ...props }, ref) => /* @__PURE__ */
|
|
552
|
+
({ className, ...props }, ref) => /* @__PURE__ */ jsx3("h3", { ref, className: cn("fractal-card-title", className), ...props })
|
|
182
553
|
);
|
|
183
554
|
CardTitle.displayName = "CardTitle";
|
|
184
555
|
var CardDescription = React2.forwardRef(
|
|
185
|
-
({ className, ...props }, ref) => /* @__PURE__ */
|
|
556
|
+
({ className, ...props }, ref) => /* @__PURE__ */ jsx3("p", { ref, className: cn("fractal-card-description", className), ...props })
|
|
186
557
|
);
|
|
187
558
|
CardDescription.displayName = "CardDescription";
|
|
188
559
|
var CardContent = React2.forwardRef(
|
|
189
|
-
({ className, ...props }, ref) => /* @__PURE__ */
|
|
560
|
+
({ className, ...props }, ref) => /* @__PURE__ */ jsx3("div", { ref, className: cn("fractal-card-content", className), ...props })
|
|
190
561
|
);
|
|
191
562
|
CardContent.displayName = "CardContent";
|
|
192
563
|
var CardFooter = React2.forwardRef(
|
|
193
|
-
({ className, ...props }, ref) => /* @__PURE__ */
|
|
564
|
+
({ className, ...props }, ref) => /* @__PURE__ */ jsx3("div", { ref, className: cn("fractal-card-footer", className), ...props })
|
|
194
565
|
);
|
|
195
566
|
CardFooter.displayName = "CardFooter";
|
|
196
567
|
var FeatureCard = React2.forwardRef(
|
|
197
|
-
({ icon, title, description, className, ...props }, ref) => /* @__PURE__ */
|
|
198
|
-
icon && /* @__PURE__ */
|
|
199
|
-
/* @__PURE__ */
|
|
200
|
-
/* @__PURE__ */
|
|
568
|
+
({ icon, title, description, className, ...props }, ref) => /* @__PURE__ */ jsxs4("div", { ref, className: cn("fractal-feature-card", className), ...props, children: [
|
|
569
|
+
icon && /* @__PURE__ */ jsx3("div", { className: "fractal-feature-card__icon", children: icon }),
|
|
570
|
+
/* @__PURE__ */ jsx3("h3", { className: "fractal-feature-card__title", children: title }),
|
|
571
|
+
/* @__PURE__ */ jsx3("p", { className: "fractal-feature-card__description", children: description })
|
|
201
572
|
] })
|
|
202
573
|
);
|
|
203
574
|
FeatureCard.displayName = "FeatureCard";
|
|
204
575
|
var FolderCard = React2.forwardRef(
|
|
205
|
-
({ name, sessionCount, selected, className, onClick, ...props }, ref) => /* @__PURE__ */
|
|
576
|
+
({ name, sessionCount, selected, className, onClick, ...props }, ref) => /* @__PURE__ */ jsxs4(
|
|
206
577
|
"div",
|
|
207
578
|
{
|
|
208
579
|
ref,
|
|
@@ -218,11 +589,11 @@ var FolderCard = React2.forwardRef(
|
|
|
218
589
|
className: cn("fractal-folder-card", selected && "fractal-folder-card--selected", className),
|
|
219
590
|
...props,
|
|
220
591
|
children: [
|
|
221
|
-
/* @__PURE__ */
|
|
222
|
-
/* @__PURE__ */
|
|
223
|
-
/* @__PURE__ */
|
|
592
|
+
/* @__PURE__ */ jsxs4("div", { className: "fractal-folder-card__header", children: [
|
|
593
|
+
/* @__PURE__ */ jsx3(FolderIcon, { size: 16, className: "fractal-folder-card__icon", "aria-hidden": true }),
|
|
594
|
+
/* @__PURE__ */ jsx3("span", { className: "fractal-folder-card__name", children: name })
|
|
224
595
|
] }),
|
|
225
|
-
sessionCount !== void 0 && /* @__PURE__ */
|
|
596
|
+
sessionCount !== void 0 && /* @__PURE__ */ jsx3("div", { className: "fractal-folder-card__footer", children: /* @__PURE__ */ jsxs4("span", { className: "fractal-folder-card__sessions", children: [
|
|
226
597
|
sessionCount,
|
|
227
598
|
" ",
|
|
228
599
|
sessionCount === 1 ? "session" : "sessions"
|
|
@@ -235,7 +606,7 @@ FolderCard.displayName = "FolderCard";
|
|
|
235
606
|
|
|
236
607
|
// src/components/PromptCard/PromptCard.tsx
|
|
237
608
|
import * as React3 from "react";
|
|
238
|
-
import { jsx as
|
|
609
|
+
import { jsx as jsx4, jsxs as jsxs5 } from "react/jsx-runtime";
|
|
239
610
|
var titleToPrompt = (title) => typeof title === "string" || typeof title === "number" ? String(title) : "";
|
|
240
611
|
var PromptCard = React3.forwardRef(
|
|
241
612
|
({
|
|
@@ -256,7 +627,7 @@ var PromptCard = React3.forwardRef(
|
|
|
256
627
|
onPromptSelect?.(prompt ?? titleToPrompt(title));
|
|
257
628
|
}
|
|
258
629
|
};
|
|
259
|
-
return /* @__PURE__ */
|
|
630
|
+
return /* @__PURE__ */ jsxs5(
|
|
260
631
|
"button",
|
|
261
632
|
{
|
|
262
633
|
ref,
|
|
@@ -271,8 +642,8 @@ var PromptCard = React3.forwardRef(
|
|
|
271
642
|
onClick: handleClick,
|
|
272
643
|
...props,
|
|
273
644
|
children: [
|
|
274
|
-
icon && /* @__PURE__ */
|
|
275
|
-
/* @__PURE__ */
|
|
645
|
+
icon && /* @__PURE__ */ jsx4("span", { className: "fractal-prompt-card__icon", "aria-hidden": "true", children: icon }),
|
|
646
|
+
/* @__PURE__ */ jsx4("span", { className: "fractal-prompt-card__title", children: title })
|
|
276
647
|
]
|
|
277
648
|
}
|
|
278
649
|
);
|
|
@@ -280,7 +651,7 @@ var PromptCard = React3.forwardRef(
|
|
|
280
651
|
);
|
|
281
652
|
PromptCard.displayName = "PromptCard";
|
|
282
653
|
var PromptGrid = React3.forwardRef(
|
|
283
|
-
({ compact, padded, className, ...props }, ref) => /* @__PURE__ */
|
|
654
|
+
({ compact, padded, className, ...props }, ref) => /* @__PURE__ */ jsx4(
|
|
284
655
|
"div",
|
|
285
656
|
{
|
|
286
657
|
ref,
|
|
@@ -298,9 +669,9 @@ PromptGrid.displayName = "PromptGrid";
|
|
|
298
669
|
|
|
299
670
|
// src/components/Input/Input.tsx
|
|
300
671
|
import * as React4 from "react";
|
|
301
|
-
import { jsx as
|
|
672
|
+
import { jsx as jsx5 } from "react/jsx-runtime";
|
|
302
673
|
var Input = React4.forwardRef(
|
|
303
|
-
({ className, type, ...props }, ref) => /* @__PURE__ */
|
|
674
|
+
({ className, type, ...props }, ref) => /* @__PURE__ */ jsx5(
|
|
304
675
|
"input",
|
|
305
676
|
{
|
|
306
677
|
type,
|
|
@@ -312,11 +683,181 @@ var Input = React4.forwardRef(
|
|
|
312
683
|
);
|
|
313
684
|
Input.displayName = "Input";
|
|
314
685
|
|
|
315
|
-
// src/components/
|
|
686
|
+
// src/components/TableSearch/TableSearch.tsx
|
|
316
687
|
import * as React5 from "react";
|
|
317
|
-
import {
|
|
318
|
-
|
|
319
|
-
|
|
688
|
+
import { MagnifyingGlass, MagnifyingGlassLines } from "@mirror-physics/fractal-icons";
|
|
689
|
+
import { jsx as jsx6, jsxs as jsxs6 } from "react/jsx-runtime";
|
|
690
|
+
var TableSearch = React5.forwardRef(
|
|
691
|
+
({
|
|
692
|
+
searchType = "text",
|
|
693
|
+
className,
|
|
694
|
+
inputClassName,
|
|
695
|
+
placeholder,
|
|
696
|
+
title,
|
|
697
|
+
...props
|
|
698
|
+
}, ref) => {
|
|
699
|
+
const isGlob = searchType === "glob";
|
|
700
|
+
const SearchIcon = isGlob ? MagnifyingGlassLines : MagnifyingGlass;
|
|
701
|
+
return /* @__PURE__ */ jsxs6(
|
|
702
|
+
"div",
|
|
703
|
+
{
|
|
704
|
+
className: cn("fractal-table-search", className),
|
|
705
|
+
"data-search-type": searchType,
|
|
706
|
+
children: [
|
|
707
|
+
/* @__PURE__ */ jsx6(SearchIcon, { className: "fractal-table-search__icon", size: 17, "aria-hidden": "true" }),
|
|
708
|
+
/* @__PURE__ */ jsx6(
|
|
709
|
+
Input,
|
|
710
|
+
{
|
|
711
|
+
...props,
|
|
712
|
+
ref,
|
|
713
|
+
type: "search",
|
|
714
|
+
className: cn("fractal-table-search__input", inputClassName),
|
|
715
|
+
placeholder: placeholder ?? (isGlob ? "Glob search \u2014 use *, ?, or [a-z]" : "Search"),
|
|
716
|
+
title: title ?? (isGlob ? "Glob pattern: *, **, ?, [abc], [a-z], and [!abc]" : void 0)
|
|
717
|
+
}
|
|
718
|
+
)
|
|
719
|
+
]
|
|
720
|
+
}
|
|
721
|
+
);
|
|
722
|
+
}
|
|
723
|
+
);
|
|
724
|
+
TableSearch.displayName = "TableSearch";
|
|
725
|
+
|
|
726
|
+
// src/components/NumberInput/NumberInput.tsx
|
|
727
|
+
import * as React6 from "react";
|
|
728
|
+
import { Minus, Plus } from "@mirror-physics/fractal-icons";
|
|
729
|
+
import { jsx as jsx7, jsxs as jsxs7 } from "react/jsx-runtime";
|
|
730
|
+
function NumberInput({
|
|
731
|
+
unit,
|
|
732
|
+
className,
|
|
733
|
+
value,
|
|
734
|
+
defaultValue,
|
|
735
|
+
disabled,
|
|
736
|
+
readOnly,
|
|
737
|
+
min,
|
|
738
|
+
max,
|
|
739
|
+
...props
|
|
740
|
+
}) {
|
|
741
|
+
const inputRef = React6.useRef(null);
|
|
742
|
+
const numericValue = Number(value ?? defaultValue);
|
|
743
|
+
const characterCount = Math.max(String(value ?? defaultValue ?? "").length, 1);
|
|
744
|
+
const controlLabel = typeof props["aria-label"] === "string" ? props["aria-label"] : "value";
|
|
745
|
+
const decrementDisabled = disabled || readOnly || Number.isFinite(numericValue) && min !== void 0 && numericValue <= Number(min);
|
|
746
|
+
const incrementDisabled = disabled || readOnly || Number.isFinite(numericValue) && max !== void 0 && numericValue >= Number(max);
|
|
747
|
+
const changeByStep = (direction) => {
|
|
748
|
+
const input = inputRef.current;
|
|
749
|
+
if (!input) return;
|
|
750
|
+
if (direction === -1) input.stepDown();
|
|
751
|
+
else input.stepUp();
|
|
752
|
+
input.dispatchEvent(new Event("input", { bubbles: true }));
|
|
753
|
+
input.focus();
|
|
754
|
+
};
|
|
755
|
+
return /* @__PURE__ */ jsxs7("div", { className: cn("fractal-number-input", unit && "fractal-number-input--with-unit", className), children: [
|
|
756
|
+
/* @__PURE__ */ jsx7(
|
|
757
|
+
Input,
|
|
758
|
+
{
|
|
759
|
+
ref: inputRef,
|
|
760
|
+
type: "number",
|
|
761
|
+
value,
|
|
762
|
+
defaultValue,
|
|
763
|
+
disabled,
|
|
764
|
+
readOnly,
|
|
765
|
+
min,
|
|
766
|
+
max,
|
|
767
|
+
...props
|
|
768
|
+
}
|
|
769
|
+
),
|
|
770
|
+
unit && /* @__PURE__ */ jsx7(
|
|
771
|
+
"span",
|
|
772
|
+
{
|
|
773
|
+
className: "fractal-number-input-unit",
|
|
774
|
+
style: { left: `calc(var(--space-3, 12px) + ${characterCount}ch)` },
|
|
775
|
+
"aria-hidden": "true",
|
|
776
|
+
children: unit
|
|
777
|
+
}
|
|
778
|
+
),
|
|
779
|
+
/* @__PURE__ */ jsxs7("div", { className: "fractal-number-input-controls", children: [
|
|
780
|
+
/* @__PURE__ */ jsx7(
|
|
781
|
+
"button",
|
|
782
|
+
{
|
|
783
|
+
type: "button",
|
|
784
|
+
className: "fractal-number-input-step",
|
|
785
|
+
"aria-label": `Decrease ${controlLabel}`,
|
|
786
|
+
disabled: decrementDisabled,
|
|
787
|
+
onClick: () => changeByStep(-1),
|
|
788
|
+
children: /* @__PURE__ */ jsx7(Minus, { "aria-hidden": "true", size: 16 })
|
|
789
|
+
}
|
|
790
|
+
),
|
|
791
|
+
/* @__PURE__ */ jsx7(
|
|
792
|
+
"button",
|
|
793
|
+
{
|
|
794
|
+
type: "button",
|
|
795
|
+
className: "fractal-number-input-step",
|
|
796
|
+
"aria-label": `Increase ${controlLabel}`,
|
|
797
|
+
disabled: incrementDisabled,
|
|
798
|
+
onClick: () => changeByStep(1),
|
|
799
|
+
children: /* @__PURE__ */ jsx7(Plus, { "aria-hidden": "true", size: 16 })
|
|
800
|
+
}
|
|
801
|
+
)
|
|
802
|
+
] })
|
|
803
|
+
] });
|
|
804
|
+
}
|
|
805
|
+
|
|
806
|
+
// src/components/PasswordInput/PasswordInput.tsx
|
|
807
|
+
import * as React7 from "react";
|
|
808
|
+
import { Eye, EyeSlash } from "@mirror-physics/fractal-icons";
|
|
809
|
+
import { jsx as jsx8, jsxs as jsxs8 } from "react/jsx-runtime";
|
|
810
|
+
var PasswordInput = React7.forwardRef(
|
|
811
|
+
({
|
|
812
|
+
className,
|
|
813
|
+
disabled,
|
|
814
|
+
showPasswordLabel = "Show password",
|
|
815
|
+
hidePasswordLabel = "Hide password",
|
|
816
|
+
...props
|
|
817
|
+
}, ref) => {
|
|
818
|
+
const [passwordVisible, setPasswordVisible] = React7.useState(false);
|
|
819
|
+
const toggleLabel = passwordVisible ? hidePasswordLabel : showPasswordLabel;
|
|
820
|
+
return /* @__PURE__ */ jsxs8(
|
|
821
|
+
"div",
|
|
822
|
+
{
|
|
823
|
+
className: cn("fractal-password-input", className),
|
|
824
|
+
"data-password-visible": passwordVisible ? "" : void 0,
|
|
825
|
+
children: [
|
|
826
|
+
/* @__PURE__ */ jsx8(
|
|
827
|
+
Input,
|
|
828
|
+
{
|
|
829
|
+
...props,
|
|
830
|
+
ref,
|
|
831
|
+
className: "fractal-password-input-field",
|
|
832
|
+
disabled,
|
|
833
|
+
type: passwordVisible ? "text" : "password"
|
|
834
|
+
}
|
|
835
|
+
),
|
|
836
|
+
/* @__PURE__ */ jsx8(
|
|
837
|
+
"button",
|
|
838
|
+
{
|
|
839
|
+
type: "button",
|
|
840
|
+
className: "fractal-password-input-toggle",
|
|
841
|
+
"aria-label": toggleLabel,
|
|
842
|
+
"aria-pressed": passwordVisible,
|
|
843
|
+
disabled,
|
|
844
|
+
title: toggleLabel,
|
|
845
|
+
onClick: () => setPasswordVisible((visible) => !visible),
|
|
846
|
+
children: passwordVisible ? /* @__PURE__ */ jsx8(EyeSlash, { "aria-hidden": "true", size: 18 }) : /* @__PURE__ */ jsx8(Eye, { "aria-hidden": "true", size: 18 })
|
|
847
|
+
}
|
|
848
|
+
)
|
|
849
|
+
]
|
|
850
|
+
}
|
|
851
|
+
);
|
|
852
|
+
}
|
|
853
|
+
);
|
|
854
|
+
PasswordInput.displayName = "PasswordInput";
|
|
855
|
+
|
|
856
|
+
// src/components/Label/Label.tsx
|
|
857
|
+
import * as React8 from "react";
|
|
858
|
+
import { jsx as jsx9 } from "react/jsx-runtime";
|
|
859
|
+
var Label = React8.forwardRef(
|
|
860
|
+
({ className, ...props }, ref) => /* @__PURE__ */ jsx9(
|
|
320
861
|
"label",
|
|
321
862
|
{
|
|
322
863
|
ref,
|
|
@@ -328,44 +869,48 @@ var Label = React5.forwardRef(
|
|
|
328
869
|
Label.displayName = "Label";
|
|
329
870
|
|
|
330
871
|
// src/components/Alert/Alert.tsx
|
|
331
|
-
import * as
|
|
332
|
-
import {
|
|
872
|
+
import * as React9 from "react";
|
|
873
|
+
import { CircleCheck, CircleClose, CircleInfo, Warning } from "@mirror-physics/fractal-icons";
|
|
874
|
+
import { jsx as jsx10, jsxs as jsxs9 } from "react/jsx-runtime";
|
|
333
875
|
var defaultIcons = {
|
|
334
|
-
default:
|
|
335
|
-
info:
|
|
336
|
-
success:
|
|
337
|
-
warning:
|
|
338
|
-
error:
|
|
876
|
+
default: CircleInfo,
|
|
877
|
+
info: CircleInfo,
|
|
878
|
+
success: CircleCheck,
|
|
879
|
+
warning: Warning,
|
|
880
|
+
error: CircleClose
|
|
339
881
|
};
|
|
340
|
-
var Alert =
|
|
341
|
-
({ className, variant = "default", icon, children, ...props }, ref) =>
|
|
342
|
-
|
|
343
|
-
|
|
344
|
-
|
|
345
|
-
|
|
346
|
-
|
|
347
|
-
|
|
348
|
-
|
|
349
|
-
|
|
350
|
-
|
|
351
|
-
|
|
352
|
-
|
|
353
|
-
|
|
882
|
+
var Alert = React9.forwardRef(
|
|
883
|
+
({ className, variant = "default", icon, children, ...props }, ref) => {
|
|
884
|
+
const DefaultIcon = defaultIcons[variant];
|
|
885
|
+
return /* @__PURE__ */ jsxs9(
|
|
886
|
+
"div",
|
|
887
|
+
{
|
|
888
|
+
ref,
|
|
889
|
+
role: "alert",
|
|
890
|
+
className: cn("fractal-alert", `fractal-alert--${variant}`, className),
|
|
891
|
+
...props,
|
|
892
|
+
children: [
|
|
893
|
+
/* @__PURE__ */ jsx10("span", { className: "fractal-alert-icon", "aria-hidden": true, children: icon ?? /* @__PURE__ */ jsx10(DefaultIcon, { size: 18 }) }),
|
|
894
|
+
/* @__PURE__ */ jsx10("div", { className: "fractal-alert-content", children })
|
|
895
|
+
]
|
|
896
|
+
}
|
|
897
|
+
);
|
|
898
|
+
}
|
|
354
899
|
);
|
|
355
900
|
Alert.displayName = "Alert";
|
|
356
|
-
var AlertTitle =
|
|
357
|
-
({ className, ...props }, ref) => /* @__PURE__ */
|
|
901
|
+
var AlertTitle = React9.forwardRef(
|
|
902
|
+
({ className, ...props }, ref) => /* @__PURE__ */ jsx10("h5", { ref, className: cn("fractal-alert-title", className), ...props })
|
|
358
903
|
);
|
|
359
904
|
AlertTitle.displayName = "AlertTitle";
|
|
360
|
-
var AlertDescription =
|
|
361
|
-
({ className, ...props }, ref) => /* @__PURE__ */
|
|
905
|
+
var AlertDescription = React9.forwardRef(
|
|
906
|
+
({ className, ...props }, ref) => /* @__PURE__ */ jsx10("div", { ref, className: cn("fractal-alert-description", className), ...props })
|
|
362
907
|
);
|
|
363
908
|
AlertDescription.displayName = "AlertDescription";
|
|
364
909
|
|
|
365
910
|
// src/components/Toggle/Toggle.tsx
|
|
366
|
-
import { jsx as
|
|
911
|
+
import { jsx as jsx11, jsxs as jsxs10 } from "react/jsx-runtime";
|
|
367
912
|
function Toggle({ checked, onChange, label, className }) {
|
|
368
|
-
return /* @__PURE__ */
|
|
913
|
+
return /* @__PURE__ */ jsxs10(
|
|
369
914
|
"button",
|
|
370
915
|
{
|
|
371
916
|
type: "button",
|
|
@@ -374,18 +919,19 @@ function Toggle({ checked, onChange, label, className }) {
|
|
|
374
919
|
className: cn("fractal-toggle", className),
|
|
375
920
|
onClick: () => onChange(!checked),
|
|
376
921
|
children: [
|
|
377
|
-
/* @__PURE__ */
|
|
378
|
-
label && /* @__PURE__ */
|
|
922
|
+
/* @__PURE__ */ jsx11("span", { className: cn("fractal-toggle-track", checked && "fractal-toggle-track--checked"), children: /* @__PURE__ */ jsx11("span", { className: cn("fractal-toggle-thumb", checked && "fractal-toggle-thumb--checked") }) }),
|
|
923
|
+
label && /* @__PURE__ */ jsx11("span", { className: "fractal-toggle-label", children: label })
|
|
379
924
|
]
|
|
380
925
|
}
|
|
381
926
|
);
|
|
382
927
|
}
|
|
383
928
|
|
|
384
929
|
// src/components/Modal/Modal.tsx
|
|
930
|
+
import * as React10 from "react";
|
|
385
931
|
import { createPortal } from "react-dom";
|
|
386
932
|
|
|
387
933
|
// src/hooks/useEscapeDismiss.ts
|
|
388
|
-
import { useEffect, useRef } from "react";
|
|
934
|
+
import { useEffect as useEffect2, useRef as useRef3 } from "react";
|
|
389
935
|
var nextId = 0;
|
|
390
936
|
var stack = [];
|
|
391
937
|
function insertSorted(entry) {
|
|
@@ -418,9 +964,9 @@ function ensureGlobalListener() {
|
|
|
418
964
|
);
|
|
419
965
|
}
|
|
420
966
|
function useEscapeDismiss(priority, handler, enabled = true) {
|
|
421
|
-
const handlerRef =
|
|
967
|
+
const handlerRef = useRef3(handler);
|
|
422
968
|
handlerRef.current = handler;
|
|
423
|
-
|
|
969
|
+
useEffect2(() => {
|
|
424
970
|
if (!enabled) return;
|
|
425
971
|
ensureGlobalListener();
|
|
426
972
|
const id = nextId++;
|
|
@@ -434,27 +980,99 @@ function useEscapeDismiss(priority, handler, enabled = true) {
|
|
|
434
980
|
}, [priority, enabled]);
|
|
435
981
|
}
|
|
436
982
|
|
|
983
|
+
// src/components/UILoader/UILoader.tsx
|
|
984
|
+
import { useId } from "react";
|
|
985
|
+
import { jsx as jsx12, jsxs as jsxs11 } from "react/jsx-runtime";
|
|
986
|
+
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";
|
|
987
|
+
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";
|
|
988
|
+
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";
|
|
989
|
+
function UILoader({ size = 48, tone = "neutral", className, style, label = "Loading", ariaHidden = false }) {
|
|
990
|
+
const rawId = useId().replace(/[^a-zA-Z0-9_-]/g, "");
|
|
991
|
+
const clipId = `fractal-ui-loader-clip-${rawId}`;
|
|
992
|
+
const gradientId = `fractal-ui-loader-gradient-${rawId}`;
|
|
993
|
+
const height = typeof size === "number" ? `${size}px` : size;
|
|
994
|
+
return /* @__PURE__ */ jsx12(
|
|
995
|
+
"span",
|
|
996
|
+
{
|
|
997
|
+
"aria-hidden": ariaHidden || void 0,
|
|
998
|
+
"aria-label": ariaHidden ? void 0 : label,
|
|
999
|
+
className: cn("fractal-ui-loader", `fractal-ui-loader--${tone}`, className),
|
|
1000
|
+
role: ariaHidden ? void 0 : "status",
|
|
1001
|
+
style,
|
|
1002
|
+
children: /* @__PURE__ */ jsxs11("svg", { "aria-hidden": "true", fill: "none", viewBox: "0 0 144 92", style: { height, width: "auto" }, children: [
|
|
1003
|
+
/* @__PURE__ */ jsxs11("defs", { children: [
|
|
1004
|
+
/* @__PURE__ */ jsxs11("linearGradient", { id: gradientId, x1: "59", x2: "94.3", y1: "0", y2: "89.1", gradientUnits: "userSpaceOnUse", children: [
|
|
1005
|
+
/* @__PURE__ */ jsx12("stop", { className: "fractal-ui-loader__stop-start", offset: "0" }),
|
|
1006
|
+
/* @__PURE__ */ jsx12("stop", { className: "fractal-ui-loader__stop-end", offset: "1" })
|
|
1007
|
+
] }),
|
|
1008
|
+
/* @__PURE__ */ jsxs11("linearGradient", { id: `${gradientId}-shine`, x1: "0", x2: "1", y1: "0", y2: "0", children: [
|
|
1009
|
+
/* @__PURE__ */ jsx12("stop", { offset: "0.4", stopColor: "white", stopOpacity: "0" }),
|
|
1010
|
+
/* @__PURE__ */ jsx12("stop", { offset: "0.5", stopColor: "white", stopOpacity: "0.62" }),
|
|
1011
|
+
/* @__PURE__ */ jsx12("stop", { offset: "0.6", stopColor: "white", stopOpacity: "0" })
|
|
1012
|
+
] }),
|
|
1013
|
+
/* @__PURE__ */ jsxs11("clipPath", { id: clipId, children: [
|
|
1014
|
+
/* @__PURE__ */ jsx12("path", { d: LEFT }),
|
|
1015
|
+
/* @__PURE__ */ jsx12("path", { d: CENTER }),
|
|
1016
|
+
/* @__PURE__ */ jsx12("path", { d: RIGHT })
|
|
1017
|
+
] })
|
|
1018
|
+
] }),
|
|
1019
|
+
/* @__PURE__ */ jsx12("path", { d: CENTER, fill: `url(#${gradientId})` }),
|
|
1020
|
+
/* @__PURE__ */ jsx12("path", { d: RIGHT, fill: `url(#${gradientId})` }),
|
|
1021
|
+
/* @__PURE__ */ jsx12("path", { d: LEFT, fill: `url(#${gradientId})` }),
|
|
1022
|
+
/* @__PURE__ */ jsx12("g", { clipPath: `url(#${clipId})`, children: /* @__PURE__ */ jsx12("g", { className: "fractal-ui-loader__shine-axis", transform: "translate(72 46) rotate(68.4)", children: /* @__PURE__ */ jsx12("rect", { className: "fractal-ui-loader__shine", x: "-160", y: "-100", width: "320", height: "200", fill: `url(#${gradientId}-shine)` }) }) })
|
|
1023
|
+
] })
|
|
1024
|
+
}
|
|
1025
|
+
);
|
|
1026
|
+
}
|
|
1027
|
+
|
|
437
1028
|
// 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
|
-
|
|
1029
|
+
import { jsx as jsx13, jsxs as jsxs12 } from "react/jsx-runtime";
|
|
1030
|
+
var CloseIcon = () => /* @__PURE__ */ jsx13("svg", { width: "16", height: "16", viewBox: "0 0 16 16", fill: "none", xmlns: "http://www.w3.org/2000/svg", children: /* @__PURE__ */ jsx13("path", { d: "M12 4L4 12M4 4L12 12", stroke: "currentColor", strokeWidth: "1.5", strokeLinecap: "round", strokeLinejoin: "round" }) });
|
|
1031
|
+
function Modal({ open, onClose, title, children, danger, warn, footer, noClose, closeDisabled = false, size = "sm", loading = false, loadingLabel = "Loading", scrollable = false, className }) {
|
|
1032
|
+
const [bodyScrolled, setBodyScrolled] = React10.useState(false);
|
|
1033
|
+
useEscapeDismiss(80, onClose, open && !noClose && !closeDisabled);
|
|
1034
|
+
React10.useEffect(() => {
|
|
1035
|
+
if (open) setBodyScrolled(false);
|
|
1036
|
+
}, [open]);
|
|
442
1037
|
if (!open) return null;
|
|
443
1038
|
const sizeClass = `fractal-modal-panel--${size}`;
|
|
444
1039
|
const accentClass = danger ? "fractal-modal-panel--danger" : warn ? "fractal-modal-panel--warn" : "";
|
|
445
1040
|
return createPortal(
|
|
446
|
-
/* @__PURE__ */
|
|
1041
|
+
/* @__PURE__ */ jsx13("div", { className: "fractal-modal-overlay", onClick: noClose || closeDisabled ? void 0 : onClose, children: /* @__PURE__ */ jsxs12(
|
|
447
1042
|
"div",
|
|
448
1043
|
{
|
|
449
|
-
className: cn("fractal-modal-panel", sizeClass, accentClass, className),
|
|
1044
|
+
className: cn("fractal-modal-panel", sizeClass, accentClass, scrollable && "fractal-modal-panel--scrollable", className),
|
|
450
1045
|
onClick: (e) => e.stopPropagation(),
|
|
451
1046
|
children: [
|
|
452
|
-
/* @__PURE__ */
|
|
453
|
-
|
|
454
|
-
|
|
455
|
-
|
|
456
|
-
|
|
457
|
-
|
|
1047
|
+
/* @__PURE__ */ jsxs12(
|
|
1048
|
+
"div",
|
|
1049
|
+
{
|
|
1050
|
+
className: cn(
|
|
1051
|
+
"fractal-modal-title-row",
|
|
1052
|
+
scrollable && "fractal-modal-title-row--scrollable",
|
|
1053
|
+
scrollable && bodyScrolled && "fractal-modal-title-row--scrolled"
|
|
1054
|
+
),
|
|
1055
|
+
children: [
|
|
1056
|
+
/* @__PURE__ */ jsx13("h3", { className: cn("fractal-modal-title", danger && "fractal-modal-title--danger", warn && "fractal-modal-title--warn"), children: title }),
|
|
1057
|
+
!noClose && /* @__PURE__ */ jsx13("button", { type: "button", onClick: onClose, title: "Close", disabled: closeDisabled, className: "fractal-modal-close", children: /* @__PURE__ */ jsx13(CloseIcon, {}) })
|
|
1058
|
+
]
|
|
1059
|
+
}
|
|
1060
|
+
),
|
|
1061
|
+
/* @__PURE__ */ jsx13(
|
|
1062
|
+
"div",
|
|
1063
|
+
{
|
|
1064
|
+
"aria-busy": loading || void 0,
|
|
1065
|
+
className: cn(
|
|
1066
|
+
"fractal-modal-body",
|
|
1067
|
+
size === "lg" && "fractal-modal-body--lg",
|
|
1068
|
+
loading && "fractal-modal-body--loading",
|
|
1069
|
+
scrollable && "fractal-modal-body--scrollable"
|
|
1070
|
+
),
|
|
1071
|
+
onScroll: scrollable ? (event) => setBodyScrolled(event.currentTarget.scrollTop > 0) : void 0,
|
|
1072
|
+
children: loading ? /* @__PURE__ */ jsx13(UILoader, { label: loadingLabel }) : children
|
|
1073
|
+
}
|
|
1074
|
+
),
|
|
1075
|
+
footer && /* @__PURE__ */ jsx13("div", { className: cn("fractal-modal-footer", scrollable && "fractal-modal-footer--divided"), children: footer })
|
|
458
1076
|
]
|
|
459
1077
|
}
|
|
460
1078
|
) }),
|
|
@@ -463,17 +1081,17 @@ function Modal({ open, onClose, title, children, danger, warn, footer, noClose,
|
|
|
463
1081
|
}
|
|
464
1082
|
|
|
465
1083
|
// src/components/DataTable/DataTable.tsx
|
|
466
|
-
import { jsx as
|
|
1084
|
+
import { jsx as jsx14, jsxs as jsxs13 } from "react/jsx-runtime";
|
|
467
1085
|
function DataTable({ columns, data, emptyMessage, header, size = "md", className }) {
|
|
468
|
-
return /* @__PURE__ */
|
|
469
|
-
header && /* @__PURE__ */
|
|
470
|
-
data.length === 0 ? /* @__PURE__ */
|
|
471
|
-
/* @__PURE__ */
|
|
472
|
-
/* @__PURE__ */
|
|
1086
|
+
return /* @__PURE__ */ jsx14("div", { className: cn("fractal-datatable", `fractal-datatable--${size}`, className), children: /* @__PURE__ */ jsxs13("div", { className: "fractal-datatable-surface", children: [
|
|
1087
|
+
header && /* @__PURE__ */ jsx14("div", { className: "fractal-datatable-header", children: header }),
|
|
1088
|
+
data.length === 0 ? /* @__PURE__ */ jsx14("div", { className: "fractal-datatable-empty", children: emptyMessage || "No data" }) : /* @__PURE__ */ jsxs13("table", { className: "fractal-datatable-table", children: [
|
|
1089
|
+
/* @__PURE__ */ jsx14("thead", { children: /* @__PURE__ */ jsx14("tr", { className: "fractal-datatable-thead-row", children: columns.map((col) => /* @__PURE__ */ jsx14("th", { className: "fractal-datatable-th", style: { width: col.width }, children: col.header }, col.key)) }) }),
|
|
1090
|
+
/* @__PURE__ */ jsx14("tbody", { children: data.map((row, rowIndex) => /* @__PURE__ */ jsx14(
|
|
473
1091
|
"tr",
|
|
474
1092
|
{
|
|
475
1093
|
className: "fractal-datatable-row",
|
|
476
|
-
children: columns.map((col) => /* @__PURE__ */
|
|
1094
|
+
children: columns.map((col) => /* @__PURE__ */ jsx14("td", { className: "fractal-datatable-td", style: { width: col.width }, children: col.render(row, rowIndex) }, col.key))
|
|
477
1095
|
},
|
|
478
1096
|
rowIndex
|
|
479
1097
|
)) })
|
|
@@ -482,9 +1100,9 @@ function DataTable({ columns, data, emptyMessage, header, size = "md", className
|
|
|
482
1100
|
}
|
|
483
1101
|
|
|
484
1102
|
// src/components/Dropdown/Dropdown.tsx
|
|
485
|
-
import * as
|
|
486
|
-
import { ChevronDown, ChevronUp } from "@mirror-physics/fractal-icons";
|
|
487
|
-
import { Fragment as Fragment2, jsx as
|
|
1103
|
+
import * as React11 from "react";
|
|
1104
|
+
import { ChevronDown, ChevronLeft, ChevronRight as ChevronRight2, ChevronUp } from "@mirror-physics/fractal-icons";
|
|
1105
|
+
import { Fragment as Fragment2, jsx as jsx15, jsxs as jsxs14 } from "react/jsx-runtime";
|
|
488
1106
|
var MARGIN = 4;
|
|
489
1107
|
function Dropdown({
|
|
490
1108
|
items,
|
|
@@ -493,20 +1111,23 @@ function Dropdown({
|
|
|
493
1111
|
triggerLabel = "Options",
|
|
494
1112
|
direction = "down",
|
|
495
1113
|
align = "left",
|
|
1114
|
+
triggerOrientation = "horizontal",
|
|
496
1115
|
triggerContent,
|
|
497
1116
|
label,
|
|
1117
|
+
iconOnly = false,
|
|
498
1118
|
noChevron = false,
|
|
499
1119
|
size = "md",
|
|
500
1120
|
triggerVariant = "outline",
|
|
501
1121
|
className,
|
|
502
1122
|
triggerClassName,
|
|
503
1123
|
panelClassName,
|
|
504
|
-
closeOnSelect = true
|
|
1124
|
+
closeOnSelect = true,
|
|
1125
|
+
disabled = false
|
|
505
1126
|
}) {
|
|
506
|
-
const [open, setOpen] =
|
|
507
|
-
const triggerRef =
|
|
508
|
-
const panelRef =
|
|
509
|
-
const [panelStyle, setPanelStyle] =
|
|
1127
|
+
const [open, setOpen] = React11.useState(false);
|
|
1128
|
+
const triggerRef = React11.useRef(null);
|
|
1129
|
+
const panelRef = React11.useRef(null);
|
|
1130
|
+
const [panelStyle, setPanelStyle] = React11.useState({});
|
|
510
1131
|
const visibleItems = items.filter(
|
|
511
1132
|
(item) => item.icon != null || item.description != null && (typeof item.description === "string" ? item.description !== "" : true)
|
|
512
1133
|
);
|
|
@@ -514,42 +1135,60 @@ function Dropdown({
|
|
|
514
1135
|
const selectableItems = visibleItems.filter((i) => i.kind !== "header");
|
|
515
1136
|
const selected = items.find((i) => i.value === selectedValue && i.kind !== "header") ?? selectableItems[0] ?? visibleItems[0];
|
|
516
1137
|
const isUp = direction === "up";
|
|
517
|
-
const
|
|
518
|
-
|
|
1138
|
+
const isHorizontalDirection = direction === "left" || direction === "right";
|
|
1139
|
+
const ChevronIcon = direction === "up" ? ChevronUp : direction === "left" ? ChevronLeft : direction === "right" ? ChevronRight2 : ChevronDown;
|
|
1140
|
+
React11.useLayoutEffect(() => {
|
|
519
1141
|
if (!open || !triggerRef.current || !panelRef.current) return;
|
|
520
1142
|
const triggerRect = triggerRef.current.getBoundingClientRect();
|
|
521
1143
|
const panelRect = panelRef.current.getBoundingClientRect();
|
|
522
1144
|
const vw = window.innerWidth;
|
|
523
1145
|
const vh = window.innerHeight;
|
|
524
|
-
|
|
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;
|
|
531
|
-
}
|
|
532
|
-
const top = placeAbove ? -(panelRect.height + MARGIN) : triggerRect.height + MARGIN;
|
|
1146
|
+
let top;
|
|
533
1147
|
let left;
|
|
534
1148
|
let right;
|
|
535
|
-
if (
|
|
536
|
-
|
|
537
|
-
const
|
|
538
|
-
|
|
539
|
-
|
|
540
|
-
|
|
1149
|
+
if (isHorizontalDirection) {
|
|
1150
|
+
const spaceRight = vw - triggerRect.right - MARGIN;
|
|
1151
|
+
const spaceLeft = triggerRect.left - MARGIN;
|
|
1152
|
+
let placeRight = direction === "right";
|
|
1153
|
+
if (placeRight && panelRect.width > spaceRight && spaceLeft > spaceRight) {
|
|
1154
|
+
placeRight = false;
|
|
1155
|
+
} else if (!placeRight && panelRect.width > spaceLeft && spaceRight > spaceLeft) {
|
|
1156
|
+
placeRight = true;
|
|
541
1157
|
}
|
|
1158
|
+
left = placeRight ? triggerRect.width + MARGIN : -(panelRect.width + MARGIN);
|
|
1159
|
+
top = 0;
|
|
1160
|
+
const panelBottom = triggerRect.top + panelRect.height;
|
|
1161
|
+
if (panelBottom > vh - MARGIN) top -= panelBottom - (vh - MARGIN);
|
|
1162
|
+
if (triggerRect.top + top < MARGIN) top += MARGIN - (triggerRect.top + top);
|
|
542
1163
|
} else {
|
|
543
|
-
|
|
544
|
-
const
|
|
545
|
-
|
|
546
|
-
|
|
1164
|
+
const spaceBelow = vh - triggerRect.bottom - MARGIN;
|
|
1165
|
+
const spaceAbove = triggerRect.top - MARGIN;
|
|
1166
|
+
let placeAbove = isUp;
|
|
1167
|
+
if (placeAbove && panelRect.height > spaceAbove && spaceBelow > spaceAbove) {
|
|
1168
|
+
placeAbove = false;
|
|
1169
|
+
} else if (!placeAbove && panelRect.height > spaceBelow && spaceAbove > spaceBelow) {
|
|
1170
|
+
placeAbove = true;
|
|
1171
|
+
}
|
|
1172
|
+
top = placeAbove ? -(panelRect.height + MARGIN) : triggerRect.height + MARGIN;
|
|
1173
|
+
if (align === "right") {
|
|
547
1174
|
right = 0;
|
|
1175
|
+
const panelLeft = triggerRect.right - panelRect.width;
|
|
1176
|
+
if (panelLeft < 0) {
|
|
1177
|
+
right = void 0;
|
|
1178
|
+
left = 0;
|
|
1179
|
+
}
|
|
1180
|
+
} else {
|
|
1181
|
+
left = 0;
|
|
1182
|
+
const panelRight = triggerRect.left + panelRect.width;
|
|
1183
|
+
if (panelRight > vw) {
|
|
1184
|
+
left = void 0;
|
|
1185
|
+
right = 0;
|
|
1186
|
+
}
|
|
548
1187
|
}
|
|
549
1188
|
}
|
|
550
1189
|
setPanelStyle({ top, left, right });
|
|
551
|
-
}, [open, isUp, align]);
|
|
552
|
-
|
|
1190
|
+
}, [open, direction, isHorizontalDirection, isUp, align]);
|
|
1191
|
+
React11.useEffect(() => {
|
|
553
1192
|
if (!open) return;
|
|
554
1193
|
const handleClickOutside = (e) => {
|
|
555
1194
|
const target = e.target;
|
|
@@ -559,12 +1198,13 @@ function Dropdown({
|
|
|
559
1198
|
document.addEventListener("mousedown", handleClickOutside);
|
|
560
1199
|
return () => document.removeEventListener("mousedown", handleClickOutside);
|
|
561
1200
|
}, [open]);
|
|
562
|
-
return /* @__PURE__ */
|
|
563
|
-
/* @__PURE__ */
|
|
1201
|
+
return /* @__PURE__ */ jsxs14("div", { className: cn("fractal-dropdown", className), children: [
|
|
1202
|
+
/* @__PURE__ */ jsxs14(
|
|
564
1203
|
"button",
|
|
565
1204
|
{
|
|
566
1205
|
ref: triggerRef,
|
|
567
1206
|
type: "button",
|
|
1207
|
+
disabled,
|
|
568
1208
|
"aria-haspopup": "listbox",
|
|
569
1209
|
"aria-expanded": open,
|
|
570
1210
|
"aria-label": triggerLabel,
|
|
@@ -573,18 +1213,20 @@ function Dropdown({
|
|
|
573
1213
|
"fractal-dropdown-trigger",
|
|
574
1214
|
`fractal-dropdown-trigger--${size}`,
|
|
575
1215
|
`fractal-dropdown-trigger--${triggerVariant}`,
|
|
1216
|
+
`fractal-dropdown-trigger--${triggerOrientation}`,
|
|
1217
|
+
iconOnly && "fractal-dropdown-trigger--icon-only",
|
|
576
1218
|
triggerClassName
|
|
577
1219
|
),
|
|
578
1220
|
children: [
|
|
579
|
-
triggerContent != null ? triggerContent : /* @__PURE__ */
|
|
580
|
-
selected.icon != null && /* @__PURE__ */
|
|
581
|
-
selected.description != null && (typeof selected.description !== "string" || selected.description !== "") && /* @__PURE__ */
|
|
1221
|
+
triggerContent != null ? triggerContent : /* @__PURE__ */ jsxs14(Fragment2, { children: [
|
|
1222
|
+
selected.icon != null && /* @__PURE__ */ jsx15("span", { className: "fractal-dropdown-icon fractal-dropdown-icon--trigger", children: selected.icon }),
|
|
1223
|
+
selected.description != null && (typeof selected.description !== "string" || selected.description !== "") && /* @__PURE__ */ jsx15("span", { className: "fractal-dropdown-selected-text", children: selected.description })
|
|
582
1224
|
] }),
|
|
583
|
-
!noChevron && /* @__PURE__ */
|
|
1225
|
+
!noChevron && !iconOnly && /* @__PURE__ */ jsx15("span", { className: "fractal-dropdown-chevron", "aria-hidden": true, children: /* @__PURE__ */ jsx15(ChevronIcon, { size: size === "sm" ? 14 : 16 }) })
|
|
584
1226
|
]
|
|
585
1227
|
}
|
|
586
1228
|
),
|
|
587
|
-
open && /* @__PURE__ */
|
|
1229
|
+
open && /* @__PURE__ */ jsxs14(
|
|
588
1230
|
"div",
|
|
589
1231
|
{
|
|
590
1232
|
ref: panelRef,
|
|
@@ -593,21 +1235,21 @@ function Dropdown({
|
|
|
593
1235
|
className: cn("fractal-dropdown-panel", `fractal-dropdown-panel--${size}`, panelClassName),
|
|
594
1236
|
style: panelStyle,
|
|
595
1237
|
children: [
|
|
596
|
-
label != null && /* @__PURE__ */
|
|
1238
|
+
label != null && /* @__PURE__ */ jsx15("div", { className: "fractal-dropdown-label", children: label }),
|
|
597
1239
|
visibleItems.map((item, index) => {
|
|
598
|
-
const topDivider = item.border === "top" ? /* @__PURE__ */
|
|
599
|
-
const bottomDivider = item.border === "bottom" ? /* @__PURE__ */
|
|
1240
|
+
const topDivider = item.border === "top" ? /* @__PURE__ */ jsx15("div", { className: "fractal-dropdown-separator" }) : null;
|
|
1241
|
+
const bottomDivider = item.border === "bottom" ? /* @__PURE__ */ jsx15("div", { className: "fractal-dropdown-separator" }) : null;
|
|
600
1242
|
if (item.kind === "header") {
|
|
601
|
-
return /* @__PURE__ */
|
|
1243
|
+
return /* @__PURE__ */ jsxs14(React11.Fragment, { children: [
|
|
602
1244
|
topDivider,
|
|
603
|
-
/* @__PURE__ */
|
|
1245
|
+
/* @__PURE__ */ jsx15("div", { role: "presentation", className: "fractal-dropdown-label", children: item.description }),
|
|
604
1246
|
bottomDivider
|
|
605
1247
|
] }, `header-${index}`);
|
|
606
1248
|
}
|
|
607
1249
|
const isSelected = item.value === selectedValue;
|
|
608
|
-
return /* @__PURE__ */
|
|
1250
|
+
return /* @__PURE__ */ jsxs14(React11.Fragment, { children: [
|
|
609
1251
|
topDivider,
|
|
610
|
-
/* @__PURE__ */
|
|
1252
|
+
/* @__PURE__ */ jsxs14(
|
|
611
1253
|
"button",
|
|
612
1254
|
{
|
|
613
1255
|
type: "button",
|
|
@@ -619,9 +1261,9 @@ function Dropdown({
|
|
|
619
1261
|
},
|
|
620
1262
|
className: "fractal-dropdown-option",
|
|
621
1263
|
children: [
|
|
622
|
-
item.icon != null && /* @__PURE__ */
|
|
623
|
-
item.description != null && (typeof item.description !== "string" || item.description !== "") && /* @__PURE__ */
|
|
624
|
-
item.trailing != null && /* @__PURE__ */
|
|
1264
|
+
item.icon != null && /* @__PURE__ */ jsx15("span", { className: "fractal-dropdown-icon", children: item.icon }),
|
|
1265
|
+
item.description != null && (typeof item.description !== "string" || item.description !== "") && /* @__PURE__ */ jsx15("span", { className: "fractal-dropdown-option-text", children: item.description }),
|
|
1266
|
+
item.trailing != null && /* @__PURE__ */ jsx15("span", { className: "fractal-dropdown-trailing", children: item.trailing })
|
|
625
1267
|
]
|
|
626
1268
|
}
|
|
627
1269
|
),
|
|
@@ -635,10 +1277,10 @@ function Dropdown({
|
|
|
635
1277
|
}
|
|
636
1278
|
|
|
637
1279
|
// src/components/Link/Link.tsx
|
|
638
|
-
import * as
|
|
639
|
-
import { jsx as
|
|
640
|
-
var Link =
|
|
641
|
-
({ className, theme = "default", size = "md", ...props }, ref) => /* @__PURE__ */
|
|
1280
|
+
import * as React12 from "react";
|
|
1281
|
+
import { jsx as jsx16 } from "react/jsx-runtime";
|
|
1282
|
+
var Link = React12.forwardRef(
|
|
1283
|
+
({ className, theme = "default", size = "md", ...props }, ref) => /* @__PURE__ */ jsx16(
|
|
642
1284
|
"a",
|
|
643
1285
|
{
|
|
644
1286
|
ref,
|
|
@@ -650,10 +1292,10 @@ var Link = React8.forwardRef(
|
|
|
650
1292
|
Link.displayName = "Link";
|
|
651
1293
|
|
|
652
1294
|
// src/components/Chip/Chip.tsx
|
|
653
|
-
import * as
|
|
654
|
-
import { jsx as
|
|
655
|
-
var Chip =
|
|
656
|
-
({ className, tone = "neutral", ...props }, ref) => /* @__PURE__ */
|
|
1295
|
+
import * as React13 from "react";
|
|
1296
|
+
import { jsx as jsx17 } from "react/jsx-runtime";
|
|
1297
|
+
var Chip = React13.forwardRef(
|
|
1298
|
+
({ className, tone = "neutral", ...props }, ref) => /* @__PURE__ */ jsx17(
|
|
657
1299
|
"span",
|
|
658
1300
|
{
|
|
659
1301
|
ref,
|
|
@@ -664,36 +1306,92 @@ var Chip = React9.forwardRef(
|
|
|
664
1306
|
);
|
|
665
1307
|
Chip.displayName = "Chip";
|
|
666
1308
|
|
|
1309
|
+
// src/components/Checkbox/Checkbox.tsx
|
|
1310
|
+
import { Checkbox as CheckboxIcon, CheckboxChecked, Minus as Minus2 } from "@mirror-physics/fractal-icons";
|
|
1311
|
+
import { jsx as jsx18, jsxs as jsxs15 } from "react/jsx-runtime";
|
|
1312
|
+
function Checkbox({
|
|
1313
|
+
checked,
|
|
1314
|
+
indeterminate = false,
|
|
1315
|
+
onCheckedChange,
|
|
1316
|
+
className,
|
|
1317
|
+
disabled,
|
|
1318
|
+
onClick,
|
|
1319
|
+
onKeyDown,
|
|
1320
|
+
...props
|
|
1321
|
+
}) {
|
|
1322
|
+
return /* @__PURE__ */ jsx18(
|
|
1323
|
+
"button",
|
|
1324
|
+
{
|
|
1325
|
+
...props,
|
|
1326
|
+
className: cn(
|
|
1327
|
+
"fractal-checkbox",
|
|
1328
|
+
(checked || indeterminate) && "fractal-checkbox--checked",
|
|
1329
|
+
indeterminate && "fractal-checkbox--indeterminate",
|
|
1330
|
+
className
|
|
1331
|
+
),
|
|
1332
|
+
type: "button",
|
|
1333
|
+
role: "checkbox",
|
|
1334
|
+
"aria-checked": indeterminate ? "mixed" : checked,
|
|
1335
|
+
disabled,
|
|
1336
|
+
onClick: (event) => {
|
|
1337
|
+
onClick?.(event);
|
|
1338
|
+
if (!event.defaultPrevented) onCheckedChange(indeterminate || !checked);
|
|
1339
|
+
},
|
|
1340
|
+
onKeyDown: (event) => {
|
|
1341
|
+
onKeyDown?.(event);
|
|
1342
|
+
if (event.key === " " || event.key === "Enter") event.stopPropagation();
|
|
1343
|
+
},
|
|
1344
|
+
children: indeterminate ? /* @__PURE__ */ jsxs15("span", { className: "fractal-checkbox__indeterminate-icon", "aria-hidden": "true", children: [
|
|
1345
|
+
/* @__PURE__ */ jsx18(CheckboxIcon, { size: 18 }),
|
|
1346
|
+
/* @__PURE__ */ jsx18(Minus2, { className: "fractal-checkbox__indeterminate-mark", size: 12 })
|
|
1347
|
+
] }) : checked ? /* @__PURE__ */ jsx18(CheckboxChecked, { "aria-hidden": "true", size: 18 }) : /* @__PURE__ */ jsx18(CheckboxIcon, { "aria-hidden": "true", size: 18 })
|
|
1348
|
+
}
|
|
1349
|
+
);
|
|
1350
|
+
}
|
|
1351
|
+
|
|
667
1352
|
// src/components/SortableTable/SortableTable.tsx
|
|
668
|
-
import { useMemo, useState as
|
|
1353
|
+
import { useMemo as useMemo2, useState as useState6 } from "react";
|
|
669
1354
|
import { ArrowUp, ArrowDown, ArrowsUpDown } from "@mirror-physics/fractal-icons";
|
|
670
|
-
import { jsx as
|
|
1355
|
+
import { jsx as jsx19, jsxs as jsxs16 } from "react/jsx-runtime";
|
|
671
1356
|
function SortableTable({
|
|
672
1357
|
columns,
|
|
673
1358
|
data,
|
|
1359
|
+
"aria-label": ariaLabel,
|
|
674
1360
|
emptyMessage,
|
|
675
1361
|
header,
|
|
676
1362
|
size = "md",
|
|
1363
|
+
embedded = false,
|
|
677
1364
|
className,
|
|
1365
|
+
defaultSort,
|
|
678
1366
|
defaultSortKey = void 0,
|
|
679
1367
|
defaultSortDirection = null,
|
|
680
1368
|
sortKey: controlledKey,
|
|
681
1369
|
sortDirection: controlledDirection,
|
|
682
1370
|
onSortChange,
|
|
1371
|
+
pagination,
|
|
683
1372
|
highlightRow,
|
|
684
|
-
|
|
1373
|
+
selection,
|
|
1374
|
+
isRowDisabled,
|
|
1375
|
+
isRowSelectionDisabled,
|
|
1376
|
+
onRowClick,
|
|
1377
|
+
onRowDoubleClick,
|
|
1378
|
+
rowAction
|
|
685
1379
|
}) {
|
|
686
|
-
const [internalKey, setInternalKey] =
|
|
687
|
-
const [internalDirection, setInternalDirection] =
|
|
1380
|
+
const [internalKey, setInternalKey] = useState6(defaultSortKey ?? null);
|
|
1381
|
+
const [internalDirection, setInternalDirection] = useState6(defaultSortDirection);
|
|
688
1382
|
const isControlled = controlledKey !== void 0 && controlledDirection !== void 0;
|
|
689
1383
|
const activeKey = isControlled ? controlledKey : internalKey;
|
|
690
1384
|
const activeDirection = isControlled ? controlledDirection : internalDirection;
|
|
691
|
-
const
|
|
692
|
-
|
|
693
|
-
|
|
1385
|
+
const baselineKey = defaultSort?.key ?? null;
|
|
1386
|
+
const baselineDirection = defaultSort?.direction ?? null;
|
|
1387
|
+
const effectiveKey = activeKey && activeDirection ? activeKey : baselineKey;
|
|
1388
|
+
const effectiveDirection = activeKey && activeDirection ? activeDirection : baselineDirection;
|
|
1389
|
+
const sorted = useMemo2(() => {
|
|
1390
|
+
if (!effectiveKey || !effectiveDirection) return data;
|
|
1391
|
+
const col = columns.find((c) => c.key === effectiveKey);
|
|
694
1392
|
if (!col) return data;
|
|
695
1393
|
const accessor = col.sortAccessor ?? ((row) => {
|
|
696
|
-
const value = row[
|
|
1394
|
+
const value = row[effectiveKey];
|
|
697
1395
|
return typeof value === "string" || typeof value === "number" ? value : null;
|
|
698
1396
|
});
|
|
699
1397
|
const copy = [...data];
|
|
@@ -704,26 +1402,41 @@ function SortableTable({
|
|
|
704
1402
|
if (av == null) return 1;
|
|
705
1403
|
if (bv == null) return -1;
|
|
706
1404
|
if (typeof av === "number" && typeof bv === "number") {
|
|
707
|
-
return
|
|
1405
|
+
return effectiveDirection === "asc" ? av - bv : bv - av;
|
|
708
1406
|
}
|
|
709
1407
|
const as = String(av).toLowerCase();
|
|
710
1408
|
const bs = String(bv).toLowerCase();
|
|
711
|
-
if (as < bs) return
|
|
712
|
-
if (as > bs) return
|
|
1409
|
+
if (as < bs) return effectiveDirection === "asc" ? -1 : 1;
|
|
1410
|
+
if (as > bs) return effectiveDirection === "asc" ? 1 : -1;
|
|
713
1411
|
return 0;
|
|
714
1412
|
});
|
|
715
1413
|
return copy;
|
|
716
|
-
}, [data, columns,
|
|
1414
|
+
}, [data, columns, effectiveKey, effectiveDirection]);
|
|
1415
|
+
const visibleRows = useMemo2(() => {
|
|
1416
|
+
if (!pagination) return sorted;
|
|
1417
|
+
const pageSize = Math.max(1, pagination.pageSize);
|
|
1418
|
+
const totalPages = Math.max(1, Math.ceil(sorted.length / pageSize));
|
|
1419
|
+
const page = Math.min(Math.max(1, pagination.page), totalPages);
|
|
1420
|
+
const startIndex = (page - 1) * pageSize;
|
|
1421
|
+
return sorted.slice(startIndex, startIndex + pageSize);
|
|
1422
|
+
}, [pagination, sorted]);
|
|
1423
|
+
const selectedRows = selection ? sorted.filter(selection.isSelected) : [];
|
|
1424
|
+
const selectableRows = selection ? sorted.filter((row) => !isRowDisabled?.(row) && !isRowSelectionDisabled?.(row)) : [];
|
|
1425
|
+
const selectedRowCount = selection ? selectableRows.filter(selection.isSelected).length : 0;
|
|
1426
|
+
const allRowsSelected = selectableRows.length > 0 && selectedRowCount === selectableRows.length;
|
|
1427
|
+
const someRowsSelected = selectedRows.length > 0 && !allRowsSelected;
|
|
717
1428
|
const handleSortClick = (key) => {
|
|
718
1429
|
let nextDirection;
|
|
719
|
-
if (activeKey
|
|
1430
|
+
if (!activeKey || !activeDirection) {
|
|
1431
|
+
nextDirection = baselineKey === key && baselineDirection ? baselineDirection : "asc";
|
|
1432
|
+
} else if (activeKey !== key) {
|
|
720
1433
|
nextDirection = "asc";
|
|
1434
|
+
} else if (baselineKey === key && baselineDirection) {
|
|
1435
|
+
nextDirection = activeDirection === baselineDirection ? baselineDirection === "asc" ? "desc" : "asc" : null;
|
|
721
1436
|
} else if (activeDirection === "asc") {
|
|
722
1437
|
nextDirection = "desc";
|
|
723
|
-
} else if (activeDirection === "desc") {
|
|
724
|
-
nextDirection = null;
|
|
725
1438
|
} else {
|
|
726
|
-
nextDirection =
|
|
1439
|
+
nextDirection = null;
|
|
727
1440
|
}
|
|
728
1441
|
const nextKey = nextDirection === null ? null : key;
|
|
729
1442
|
if (isControlled) {
|
|
@@ -734,75 +1447,140 @@ function SortableTable({
|
|
|
734
1447
|
onSortChange?.(nextKey, nextDirection);
|
|
735
1448
|
}
|
|
736
1449
|
};
|
|
737
|
-
return /* @__PURE__ */
|
|
738
|
-
header && /* @__PURE__ */
|
|
739
|
-
|
|
740
|
-
/* @__PURE__ */
|
|
741
|
-
|
|
742
|
-
|
|
743
|
-
|
|
1450
|
+
return /* @__PURE__ */ jsx19("div", { className: cn("fractal-sortable-table", `fractal-sortable-table--${size}`, embedded && "fractal-sortable-table--embedded", className), children: /* @__PURE__ */ jsxs16("div", { className: "fractal-sortable-table-surface", children: [
|
|
1451
|
+
header && /* @__PURE__ */ jsx19("div", { className: "fractal-sortable-table-header", children: header }),
|
|
1452
|
+
visibleRows.length === 0 ? /* @__PURE__ */ jsx19("div", { className: "fractal-sortable-table-empty", children: emptyMessage || "No data" }) : /* @__PURE__ */ jsxs16("table", { "aria-label": ariaLabel, className: "fractal-sortable-table-table", children: [
|
|
1453
|
+
/* @__PURE__ */ jsx19("thead", { children: /* @__PURE__ */ jsxs16("tr", { className: "fractal-sortable-table-thead-row", children: [
|
|
1454
|
+
selection && /* @__PURE__ */ jsx19(
|
|
1455
|
+
"th",
|
|
1456
|
+
{
|
|
1457
|
+
className: "fractal-sortable-table-th fractal-sortable-table-selection-cell",
|
|
1458
|
+
scope: "col",
|
|
1459
|
+
children: /* @__PURE__ */ jsx19(
|
|
1460
|
+
Checkbox,
|
|
1461
|
+
{
|
|
1462
|
+
"aria-label": selection.selectAllLabel ?? "Select all rows",
|
|
1463
|
+
checked: allRowsSelected,
|
|
1464
|
+
disabled: selectableRows.length === 0 && selectedRows.length === 0,
|
|
1465
|
+
indeterminate: someRowsSelected,
|
|
1466
|
+
onCheckedChange: (checked) => {
|
|
1467
|
+
const rows = checked ? selectableRows : selectedRows;
|
|
1468
|
+
if (selection.onSelectAllChange) {
|
|
1469
|
+
selection.onSelectAllChange(rows, checked);
|
|
1470
|
+
return;
|
|
1471
|
+
}
|
|
1472
|
+
rows.forEach((row) => {
|
|
1473
|
+
if (selection.isSelected(row) !== checked) {
|
|
1474
|
+
selection.onSelectedChange(row, checked);
|
|
1475
|
+
}
|
|
1476
|
+
});
|
|
1477
|
+
}
|
|
1478
|
+
}
|
|
1479
|
+
)
|
|
1480
|
+
}
|
|
1481
|
+
),
|
|
1482
|
+
columns.map((col) => {
|
|
1483
|
+
const isActive = activeKey === col.key && activeDirection !== null;
|
|
1484
|
+
if (!col.sortable) {
|
|
1485
|
+
return /* @__PURE__ */ jsx19(
|
|
1486
|
+
"th",
|
|
1487
|
+
{
|
|
1488
|
+
className: "fractal-sortable-table-th",
|
|
1489
|
+
scope: "col",
|
|
1490
|
+
style: { width: col.width },
|
|
1491
|
+
children: col.header
|
|
1492
|
+
},
|
|
1493
|
+
col.key
|
|
1494
|
+
);
|
|
1495
|
+
}
|
|
1496
|
+
return /* @__PURE__ */ jsx19(
|
|
744
1497
|
"th",
|
|
745
1498
|
{
|
|
746
|
-
className: "fractal-sortable-table-th",
|
|
1499
|
+
className: "fractal-sortable-table-th fractal-sortable-table-th--sortable",
|
|
1500
|
+
scope: "col",
|
|
747
1501
|
style: { width: col.width },
|
|
748
|
-
children:
|
|
1502
|
+
children: /* @__PURE__ */ jsxs16(
|
|
1503
|
+
"button",
|
|
1504
|
+
{
|
|
1505
|
+
type: "button",
|
|
1506
|
+
className: cn(
|
|
1507
|
+
"fractal-sortable-table-sort-button",
|
|
1508
|
+
isActive && "fractal-sortable-table-sort-button--active"
|
|
1509
|
+
),
|
|
1510
|
+
onClick: () => handleSortClick(col.key),
|
|
1511
|
+
"aria-sort": isActive ? activeDirection === "asc" ? "ascending" : "descending" : "none",
|
|
1512
|
+
children: [
|
|
1513
|
+
/* @__PURE__ */ jsx19("span", { children: col.header }),
|
|
1514
|
+
/* @__PURE__ */ jsx19("span", { className: "fractal-sortable-table-sort-icon", "aria-hidden": "true", children: isActive && activeDirection === "asc" ? /* @__PURE__ */ jsx19(ArrowUp, { size: 14 }) : isActive && activeDirection === "desc" ? /* @__PURE__ */ jsx19(ArrowDown, { size: 14 }) : /* @__PURE__ */ jsx19(ArrowsUpDown, { size: 14 }) })
|
|
1515
|
+
]
|
|
1516
|
+
}
|
|
1517
|
+
)
|
|
749
1518
|
},
|
|
750
1519
|
col.key
|
|
751
1520
|
);
|
|
752
|
-
}
|
|
753
|
-
|
|
754
|
-
|
|
755
|
-
{
|
|
756
|
-
className: "fractal-sortable-table-th fractal-sortable-table-th--sortable",
|
|
757
|
-
style: { width: col.width },
|
|
758
|
-
children: /* @__PURE__ */ jsxs9(
|
|
759
|
-
"button",
|
|
760
|
-
{
|
|
761
|
-
type: "button",
|
|
762
|
-
className: cn(
|
|
763
|
-
"fractal-sortable-table-sort-button",
|
|
764
|
-
isActive && "fractal-sortable-table-sort-button--active"
|
|
765
|
-
),
|
|
766
|
-
onClick: () => handleSortClick(col.key),
|
|
767
|
-
"aria-sort": isActive ? activeDirection === "asc" ? "ascending" : "descending" : "none",
|
|
768
|
-
children: [
|
|
769
|
-
/* @__PURE__ */ jsx12("span", { children: col.header }),
|
|
770
|
-
/* @__PURE__ */ jsx12("span", { className: "fractal-sortable-table-sort-icon", "aria-hidden": "true", children: isActive && activeDirection === "asc" ? /* @__PURE__ */ jsx12(ArrowUp, { size: 14 }) : isActive && activeDirection === "desc" ? /* @__PURE__ */ jsx12(ArrowDown, { size: 14 }) : /* @__PURE__ */ jsx12(ArrowsUpDown, { size: 14 }) })
|
|
771
|
-
]
|
|
772
|
-
}
|
|
773
|
-
)
|
|
774
|
-
},
|
|
775
|
-
col.key
|
|
776
|
-
);
|
|
777
|
-
}) }) }),
|
|
778
|
-
/* @__PURE__ */ jsx12("tbody", { children: sorted.map((row, rowIndex) => {
|
|
1521
|
+
})
|
|
1522
|
+
] }) }),
|
|
1523
|
+
/* @__PURE__ */ jsx19("tbody", { children: visibleRows.map((row, rowIndex) => {
|
|
779
1524
|
const highlighted = highlightRow?.(row, rowIndex) ?? false;
|
|
780
|
-
|
|
1525
|
+
const disabled = isRowDisabled?.(row) ?? false;
|
|
1526
|
+
const selectionDisabled = disabled || (isRowSelectionDisabled?.(row) ?? false);
|
|
1527
|
+
const interactive = !disabled && Boolean(onRowClick || onRowDoubleClick);
|
|
1528
|
+
const action = !disabled && rowAction ? {
|
|
1529
|
+
label: rowAction.label(row, rowIndex),
|
|
1530
|
+
icon: rowAction.icon(row, rowIndex)
|
|
1531
|
+
} : null;
|
|
1532
|
+
return /* @__PURE__ */ jsxs16(
|
|
781
1533
|
"tr",
|
|
782
1534
|
{
|
|
783
1535
|
className: cn(
|
|
784
1536
|
"fractal-sortable-table-row",
|
|
785
1537
|
highlighted && "fractal-sortable-table-row--highlighted",
|
|
786
|
-
|
|
1538
|
+
interactive && "fractal-sortable-table-row--interactive",
|
|
1539
|
+
disabled && "fractal-sortable-table-row--disabled"
|
|
787
1540
|
),
|
|
788
|
-
|
|
789
|
-
|
|
1541
|
+
"data-disabled": disabled || void 0,
|
|
1542
|
+
onClick: !disabled && onRowClick ? () => onRowClick(row, rowIndex) : void 0,
|
|
1543
|
+
onDoubleClick: !disabled && onRowDoubleClick ? () => onRowDoubleClick(row, rowIndex) : void 0,
|
|
1544
|
+
onKeyDown: interactive ? (event) => {
|
|
790
1545
|
if (event.key === "Enter" || event.key === " ") {
|
|
791
1546
|
event.preventDefault();
|
|
792
|
-
onRowClick
|
|
1547
|
+
const activateRow = onRowClick ?? onRowDoubleClick;
|
|
1548
|
+
activateRow?.(row, rowIndex);
|
|
793
1549
|
}
|
|
794
1550
|
} : void 0,
|
|
795
|
-
|
|
796
|
-
|
|
797
|
-
|
|
798
|
-
|
|
799
|
-
|
|
800
|
-
|
|
801
|
-
|
|
802
|
-
|
|
803
|
-
|
|
804
|
-
|
|
805
|
-
|
|
1551
|
+
"aria-label": action?.label,
|
|
1552
|
+
"aria-disabled": disabled || void 0,
|
|
1553
|
+
role: interactive ? "button" : void 0,
|
|
1554
|
+
tabIndex: interactive ? 0 : void 0,
|
|
1555
|
+
children: [
|
|
1556
|
+
selection && /* @__PURE__ */ jsx19("td", { className: "fractal-sortable-table-td fractal-sortable-table-selection-cell", children: /* @__PURE__ */ jsx19(
|
|
1557
|
+
Checkbox,
|
|
1558
|
+
{
|
|
1559
|
+
"aria-label": selection.getRowLabel(row),
|
|
1560
|
+
checked: !selectionDisabled && selection.isSelected(row),
|
|
1561
|
+
disabled: selectionDisabled,
|
|
1562
|
+
onClick: (event) => event.stopPropagation(),
|
|
1563
|
+
onCheckedChange: (checked) => {
|
|
1564
|
+
if (!selectionDisabled) selection.onSelectedChange(row, checked);
|
|
1565
|
+
}
|
|
1566
|
+
}
|
|
1567
|
+
) }),
|
|
1568
|
+
columns.map((col, columnIndex) => /* @__PURE__ */ jsxs16(
|
|
1569
|
+
"td",
|
|
1570
|
+
{
|
|
1571
|
+
className: cn(
|
|
1572
|
+
"fractal-sortable-table-td",
|
|
1573
|
+
action && columnIndex === columns.length - 1 && "fractal-sortable-table-td--row-action"
|
|
1574
|
+
),
|
|
1575
|
+
style: { width: col.width, textAlign: col.align ?? "left" },
|
|
1576
|
+
children: [
|
|
1577
|
+
col.render(row, rowIndex),
|
|
1578
|
+
action && columnIndex === columns.length - 1 && /* @__PURE__ */ jsx19("span", { className: "fractal-sortable-table-row-action", "aria-hidden": "true", children: /* @__PURE__ */ jsx19("span", { className: "fractal-sortable-table-row-action__icon", children: action.icon }) })
|
|
1579
|
+
]
|
|
1580
|
+
},
|
|
1581
|
+
col.key
|
|
1582
|
+
))
|
|
1583
|
+
]
|
|
806
1584
|
},
|
|
807
1585
|
rowIndex
|
|
808
1586
|
);
|
|
@@ -812,23 +1590,40 @@ function SortableTable({
|
|
|
812
1590
|
}
|
|
813
1591
|
|
|
814
1592
|
// src/components/Tabs/Tabs.tsx
|
|
815
|
-
import { useId, useRef as
|
|
816
|
-
import { jsx as
|
|
1593
|
+
import { useId as useId2, useLayoutEffect as useLayoutEffect2, useRef as useRef5, useState as useState7 } from "react";
|
|
1594
|
+
import { jsx as jsx20, jsxs as jsxs17 } from "react/jsx-runtime";
|
|
817
1595
|
function Tabs({
|
|
818
1596
|
items,
|
|
819
1597
|
defaultValue,
|
|
820
1598
|
value: controlledValue,
|
|
821
1599
|
onValueChange,
|
|
822
1600
|
className,
|
|
823
|
-
ariaLabel
|
|
1601
|
+
ariaLabel,
|
|
1602
|
+
divider = false,
|
|
1603
|
+
variant = "line"
|
|
824
1604
|
}) {
|
|
825
|
-
const reactId =
|
|
826
|
-
const [internalValue, setInternalValue] =
|
|
1605
|
+
const reactId = useId2();
|
|
1606
|
+
const [internalValue, setInternalValue] = useState7(
|
|
827
1607
|
defaultValue ?? items.find((i) => !i.disabled)?.id ?? items[0]?.id ?? ""
|
|
828
1608
|
);
|
|
829
1609
|
const isControlled = controlledValue !== void 0;
|
|
830
1610
|
const activeId = isControlled ? controlledValue : internalValue;
|
|
831
|
-
const
|
|
1611
|
+
const tabListRef = useRef5(null);
|
|
1612
|
+
const tabRefs = useRef5({});
|
|
1613
|
+
const [indicator, setIndicator] = useState7(null);
|
|
1614
|
+
useLayoutEffect2(() => {
|
|
1615
|
+
const updateIndicator = () => {
|
|
1616
|
+
const activeTab = tabRefs.current[activeId];
|
|
1617
|
+
if (!activeTab) return;
|
|
1618
|
+
setIndicator({ offset: activeTab.offsetLeft, width: activeTab.offsetWidth });
|
|
1619
|
+
};
|
|
1620
|
+
updateIndicator();
|
|
1621
|
+
const list = tabListRef.current;
|
|
1622
|
+
if (!list || typeof ResizeObserver === "undefined") return;
|
|
1623
|
+
const observer = new ResizeObserver(updateIndicator);
|
|
1624
|
+
observer.observe(list);
|
|
1625
|
+
return () => observer.disconnect();
|
|
1626
|
+
}, [activeId, items.length]);
|
|
832
1627
|
const selectTab = (id) => {
|
|
833
1628
|
if (isControlled) {
|
|
834
1629
|
onValueChange?.(id);
|
|
@@ -838,6 +1633,10 @@ function Tabs({
|
|
|
838
1633
|
}
|
|
839
1634
|
};
|
|
840
1635
|
const focusable = items.filter((i) => !i.disabled);
|
|
1636
|
+
const indicatorStyle = indicator ? {
|
|
1637
|
+
"--fractal-tabs-indicator-offset": `${indicator.offset}px`,
|
|
1638
|
+
"--fractal-tabs-indicator-width": `${indicator.width}px`
|
|
1639
|
+
} : void 0;
|
|
841
1640
|
const onKeyDown = (event) => {
|
|
842
1641
|
const currentIndex = focusable.findIndex((i) => i.id === activeId);
|
|
843
1642
|
if (currentIndex === -1) return;
|
|
@@ -863,41 +1662,52 @@ function Tabs({
|
|
|
863
1662
|
selectTab(nextId2);
|
|
864
1663
|
requestAnimationFrame(() => tabRefs.current[nextId2]?.focus());
|
|
865
1664
|
};
|
|
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
|
-
|
|
1665
|
+
return /* @__PURE__ */ jsxs17("div", { className: cn("fractal-tabs", `fractal-tabs--${variant}`, divider && "fractal-tabs--divider", className), children: [
|
|
1666
|
+
/* @__PURE__ */ jsx20(
|
|
1667
|
+
"div",
|
|
1668
|
+
{
|
|
1669
|
+
ref: tabListRef,
|
|
1670
|
+
role: "tablist",
|
|
1671
|
+
"aria-label": ariaLabel,
|
|
1672
|
+
className: "fractal-tabs-list",
|
|
1673
|
+
"data-indicator-ready": indicator ? "true" : void 0,
|
|
1674
|
+
style: indicatorStyle,
|
|
1675
|
+
children: items.map((item) => {
|
|
1676
|
+
const isActive = item.id === activeId;
|
|
1677
|
+
const tabId = `${reactId}-tab-${item.id}`;
|
|
1678
|
+
const panelId = `${reactId}-panel-${item.id}`;
|
|
1679
|
+
return /* @__PURE__ */ jsx20(
|
|
1680
|
+
"button",
|
|
1681
|
+
{
|
|
1682
|
+
ref: (el) => {
|
|
1683
|
+
tabRefs.current[item.id] = el;
|
|
1684
|
+
},
|
|
1685
|
+
id: tabId,
|
|
1686
|
+
role: "tab",
|
|
1687
|
+
type: "button",
|
|
1688
|
+
"aria-selected": isActive,
|
|
1689
|
+
"aria-controls": panelId,
|
|
1690
|
+
tabIndex: isActive ? 0 : -1,
|
|
1691
|
+
disabled: item.disabled,
|
|
1692
|
+
className: cn(
|
|
1693
|
+
"fractal-tabs-trigger",
|
|
1694
|
+
isActive && "fractal-tabs-trigger--active",
|
|
1695
|
+
item.disabled && "fractal-tabs-trigger--disabled"
|
|
1696
|
+
),
|
|
1697
|
+
onClick: () => !item.disabled && selectTab(item.id),
|
|
1698
|
+
onKeyDown,
|
|
1699
|
+
children: item.label
|
|
1700
|
+
},
|
|
1701
|
+
item.id
|
|
1702
|
+
);
|
|
1703
|
+
})
|
|
1704
|
+
}
|
|
1705
|
+
),
|
|
896
1706
|
items.map((item) => {
|
|
897
1707
|
const tabId = `${reactId}-tab-${item.id}`;
|
|
898
1708
|
const panelId = `${reactId}-panel-${item.id}`;
|
|
899
1709
|
const isActive = item.id === activeId;
|
|
900
|
-
return /* @__PURE__ */
|
|
1710
|
+
return /* @__PURE__ */ jsx20(
|
|
901
1711
|
"div",
|
|
902
1712
|
{
|
|
903
1713
|
id: panelId,
|
|
@@ -913,10 +1723,112 @@ function Tabs({
|
|
|
913
1723
|
] });
|
|
914
1724
|
}
|
|
915
1725
|
|
|
1726
|
+
// src/components/ContentSwitcher/ContentSwitcher.tsx
|
|
1727
|
+
import * as React14 from "react";
|
|
1728
|
+
import { jsx as jsx21, jsxs as jsxs18 } from "react/jsx-runtime";
|
|
1729
|
+
function ContentSwitcher({ items, value, onValueChange, ariaLabel, fullWidth = false, className }) {
|
|
1730
|
+
const switcherRef = React14.useRef(null);
|
|
1731
|
+
const buttonRefs = React14.useRef([]);
|
|
1732
|
+
const indicatorMotionReadyRef = React14.useRef(false);
|
|
1733
|
+
const activeIndex = items.findIndex((item) => item.value === value);
|
|
1734
|
+
React14.useLayoutEffect(() => {
|
|
1735
|
+
const switcher = switcherRef.current;
|
|
1736
|
+
const activeButton = buttonRefs.current[activeIndex];
|
|
1737
|
+
let motionFrame = 0;
|
|
1738
|
+
if (!switcher || !activeButton) {
|
|
1739
|
+
switcher?.removeAttribute("data-indicator-ready");
|
|
1740
|
+
switcher?.removeAttribute("data-indicator-animate");
|
|
1741
|
+
indicatorMotionReadyRef.current = false;
|
|
1742
|
+
return;
|
|
1743
|
+
}
|
|
1744
|
+
const updateIndicator = () => {
|
|
1745
|
+
const switcherRect = switcher.getBoundingClientRect();
|
|
1746
|
+
const activeButtonRect = activeButton.getBoundingClientRect();
|
|
1747
|
+
switcher.style.setProperty("--fractal-content-switcher-indicator-x", `${activeButtonRect.left - switcherRect.left - switcher.clientLeft}px`);
|
|
1748
|
+
switcher.style.setProperty("--fractal-content-switcher-indicator-y", `${activeButtonRect.top - switcherRect.top - switcher.clientTop}px`);
|
|
1749
|
+
switcher.style.setProperty("--fractal-content-switcher-indicator-width", `${activeButtonRect.width}px`);
|
|
1750
|
+
switcher.style.setProperty("--fractal-content-switcher-indicator-height", `${activeButtonRect.height}px`);
|
|
1751
|
+
switcher.setAttribute("data-indicator-ready", "true");
|
|
1752
|
+
if (!indicatorMotionReadyRef.current && motionFrame === 0) {
|
|
1753
|
+
motionFrame = window.requestAnimationFrame(() => {
|
|
1754
|
+
indicatorMotionReadyRef.current = true;
|
|
1755
|
+
switcher.setAttribute("data-indicator-animate", "true");
|
|
1756
|
+
motionFrame = 0;
|
|
1757
|
+
});
|
|
1758
|
+
}
|
|
1759
|
+
};
|
|
1760
|
+
updateIndicator();
|
|
1761
|
+
if (typeof ResizeObserver === "undefined") {
|
|
1762
|
+
return () => {
|
|
1763
|
+
if (motionFrame !== 0) window.cancelAnimationFrame(motionFrame);
|
|
1764
|
+
};
|
|
1765
|
+
}
|
|
1766
|
+
const resizeObserver = new ResizeObserver(updateIndicator);
|
|
1767
|
+
resizeObserver.observe(switcher);
|
|
1768
|
+
buttonRefs.current.forEach((button) => {
|
|
1769
|
+
if (button) resizeObserver.observe(button);
|
|
1770
|
+
});
|
|
1771
|
+
return () => {
|
|
1772
|
+
resizeObserver.disconnect();
|
|
1773
|
+
if (motionFrame !== 0) window.cancelAnimationFrame(motionFrame);
|
|
1774
|
+
};
|
|
1775
|
+
}, [activeIndex, items.length]);
|
|
1776
|
+
const moveFocus = (index, direction) => {
|
|
1777
|
+
let nextIndex = index;
|
|
1778
|
+
do {
|
|
1779
|
+
nextIndex = (nextIndex + direction + items.length) % items.length;
|
|
1780
|
+
} while (items[nextIndex]?.disabled && nextIndex !== index);
|
|
1781
|
+
if (!items[nextIndex]?.disabled) {
|
|
1782
|
+
buttonRefs.current[nextIndex]?.focus();
|
|
1783
|
+
onValueChange(items[nextIndex].value);
|
|
1784
|
+
}
|
|
1785
|
+
};
|
|
1786
|
+
return /* @__PURE__ */ jsxs18(
|
|
1787
|
+
"div",
|
|
1788
|
+
{
|
|
1789
|
+
className: cn("fractal-content-switcher", fullWidth && "fractal-content-switcher--full-width", className),
|
|
1790
|
+
role: "group",
|
|
1791
|
+
"aria-label": ariaLabel,
|
|
1792
|
+
ref: switcherRef,
|
|
1793
|
+
children: [
|
|
1794
|
+
/* @__PURE__ */ jsx21("span", { className: "fractal-content-switcher__indicator", "aria-hidden": true }),
|
|
1795
|
+
items.map((item, index) => {
|
|
1796
|
+
const active = item.value === value;
|
|
1797
|
+
return /* @__PURE__ */ jsx21(
|
|
1798
|
+
"button",
|
|
1799
|
+
{
|
|
1800
|
+
className: cn("fractal-content-switcher__item", active && "fractal-content-switcher__item--active"),
|
|
1801
|
+
type: "button",
|
|
1802
|
+
"aria-pressed": active,
|
|
1803
|
+
disabled: item.disabled,
|
|
1804
|
+
onClick: () => onValueChange(item.value),
|
|
1805
|
+
onKeyDown: (event) => {
|
|
1806
|
+
if (event.key === "ArrowRight") {
|
|
1807
|
+
event.preventDefault();
|
|
1808
|
+
moveFocus(index, 1);
|
|
1809
|
+
}
|
|
1810
|
+
if (event.key === "ArrowLeft") {
|
|
1811
|
+
event.preventDefault();
|
|
1812
|
+
moveFocus(index, -1);
|
|
1813
|
+
}
|
|
1814
|
+
},
|
|
1815
|
+
ref: (element) => {
|
|
1816
|
+
buttonRefs.current[index] = element;
|
|
1817
|
+
},
|
|
1818
|
+
children: item.label
|
|
1819
|
+
},
|
|
1820
|
+
item.value
|
|
1821
|
+
);
|
|
1822
|
+
})
|
|
1823
|
+
]
|
|
1824
|
+
}
|
|
1825
|
+
);
|
|
1826
|
+
}
|
|
1827
|
+
|
|
916
1828
|
// src/components/Disclosure/Disclosure.tsx
|
|
917
|
-
import { useId as
|
|
918
|
-
import { ChevronRight, ChevronDown as ChevronDown2 } from "@mirror-physics/fractal-icons";
|
|
919
|
-
import { jsx as
|
|
1829
|
+
import { useId as useId3, useState as useState8 } from "react";
|
|
1830
|
+
import { ChevronRight as ChevronRight3, ChevronDown as ChevronDown2 } from "@mirror-physics/fractal-icons";
|
|
1831
|
+
import { jsx as jsx22, jsxs as jsxs19 } from "react/jsx-runtime";
|
|
920
1832
|
function Disclosure({
|
|
921
1833
|
title,
|
|
922
1834
|
meta,
|
|
@@ -924,16 +1836,18 @@ function Disclosure({
|
|
|
924
1836
|
defaultOpen = false,
|
|
925
1837
|
open: controlledOpen,
|
|
926
1838
|
onOpenChange,
|
|
1839
|
+
disabled = false,
|
|
927
1840
|
className,
|
|
928
1841
|
variant = "card"
|
|
929
1842
|
}) {
|
|
930
|
-
const reactId =
|
|
1843
|
+
const reactId = useId3();
|
|
931
1844
|
const headerId = `${reactId}-header`;
|
|
932
1845
|
const panelId = `${reactId}-panel`;
|
|
933
|
-
const [internalOpen, setInternalOpen] =
|
|
1846
|
+
const [internalOpen, setInternalOpen] = useState8(defaultOpen);
|
|
934
1847
|
const isControlled = controlledOpen !== void 0;
|
|
935
1848
|
const isOpen = isControlled ? controlledOpen : internalOpen;
|
|
936
1849
|
const toggle = () => {
|
|
1850
|
+
if (disabled) return;
|
|
937
1851
|
const next = !isOpen;
|
|
938
1852
|
if (isControlled) {
|
|
939
1853
|
onOpenChange?.(next);
|
|
@@ -942,17 +1856,18 @@ function Disclosure({
|
|
|
942
1856
|
onOpenChange?.(next);
|
|
943
1857
|
}
|
|
944
1858
|
};
|
|
945
|
-
return /* @__PURE__ */
|
|
1859
|
+
return /* @__PURE__ */ jsxs19(
|
|
946
1860
|
"div",
|
|
947
1861
|
{
|
|
948
1862
|
className: cn(
|
|
949
1863
|
"fractal-disclosure",
|
|
950
1864
|
variant === "card" && "fractal-disclosure--card",
|
|
951
1865
|
isOpen && "fractal-disclosure--open",
|
|
1866
|
+
disabled && "fractal-disclosure--disabled",
|
|
952
1867
|
className
|
|
953
1868
|
),
|
|
954
1869
|
children: [
|
|
955
|
-
/* @__PURE__ */
|
|
1870
|
+
/* @__PURE__ */ jsxs19(
|
|
956
1871
|
"button",
|
|
957
1872
|
{
|
|
958
1873
|
type: "button",
|
|
@@ -960,15 +1875,16 @@ function Disclosure({
|
|
|
960
1875
|
className: "fractal-disclosure-trigger",
|
|
961
1876
|
"aria-expanded": isOpen,
|
|
962
1877
|
"aria-controls": panelId,
|
|
1878
|
+
disabled,
|
|
963
1879
|
onClick: toggle,
|
|
964
1880
|
children: [
|
|
965
|
-
/* @__PURE__ */
|
|
966
|
-
/* @__PURE__ */
|
|
967
|
-
meta && /* @__PURE__ */
|
|
1881
|
+
/* @__PURE__ */ jsx22("span", { className: "fractal-disclosure-icon", "aria-hidden": "true", children: isOpen ? /* @__PURE__ */ jsx22(ChevronDown2, { size: 16 }) : /* @__PURE__ */ jsx22(ChevronRight3, { size: 16 }) }),
|
|
1882
|
+
/* @__PURE__ */ jsx22("span", { className: "fractal-disclosure-title", children: title }),
|
|
1883
|
+
meta && /* @__PURE__ */ jsx22("span", { className: "fractal-disclosure-meta", children: meta })
|
|
968
1884
|
]
|
|
969
1885
|
}
|
|
970
1886
|
),
|
|
971
|
-
/* @__PURE__ */
|
|
1887
|
+
/* @__PURE__ */ jsx22(
|
|
972
1888
|
"div",
|
|
973
1889
|
{
|
|
974
1890
|
id: panelId,
|
|
@@ -976,7 +1892,7 @@ function Disclosure({
|
|
|
976
1892
|
"aria-labelledby": headerId,
|
|
977
1893
|
className: "fractal-disclosure-panel",
|
|
978
1894
|
hidden: !isOpen,
|
|
979
|
-
children: /* @__PURE__ */
|
|
1895
|
+
children: /* @__PURE__ */ jsx22("div", { className: "fractal-disclosure-panel-inner", children })
|
|
980
1896
|
}
|
|
981
1897
|
)
|
|
982
1898
|
]
|
|
@@ -984,39 +1900,260 @@ function Disclosure({
|
|
|
984
1900
|
);
|
|
985
1901
|
}
|
|
986
1902
|
|
|
1903
|
+
// src/components/LatticeLoader/LatticeLoader.tsx
|
|
1904
|
+
import { jsx as jsx23 } from "react/jsx-runtime";
|
|
1905
|
+
var LATTICE_COUNT = 160;
|
|
1906
|
+
var WAVE_PERIOD = 80;
|
|
1907
|
+
function LatticeLoader({ className, label = "Loading", ...props }) {
|
|
1908
|
+
return /* @__PURE__ */ jsx23(
|
|
1909
|
+
"span",
|
|
1910
|
+
{
|
|
1911
|
+
"aria-label": label,
|
|
1912
|
+
className: cn("fractal-lattice-loader", className),
|
|
1913
|
+
role: "progressbar",
|
|
1914
|
+
...props,
|
|
1915
|
+
children: Array.from({ length: LATTICE_COUNT }, (_, index) => /* @__PURE__ */ jsx23(
|
|
1916
|
+
"span",
|
|
1917
|
+
{
|
|
1918
|
+
"aria-hidden": "true",
|
|
1919
|
+
className: "fractal-lattice-loader__cell",
|
|
1920
|
+
style: { "--fractal-lattice-index": index % WAVE_PERIOD }
|
|
1921
|
+
},
|
|
1922
|
+
index
|
|
1923
|
+
))
|
|
1924
|
+
}
|
|
1925
|
+
);
|
|
1926
|
+
}
|
|
1927
|
+
|
|
1928
|
+
// src/components/Ghost/Ghost.tsx
|
|
1929
|
+
import { jsx as jsx24, jsxs as jsxs20 } from "react/jsx-runtime";
|
|
1930
|
+
var toCssLength = (value) => typeof value === "number" ? `${value}px` : value;
|
|
1931
|
+
function Ghost({ className, width, height, radius, style, ...props }) {
|
|
1932
|
+
return /* @__PURE__ */ jsx24(
|
|
1933
|
+
"div",
|
|
1934
|
+
{
|
|
1935
|
+
"aria-hidden": "true",
|
|
1936
|
+
className: cn("fractal-ghost", className),
|
|
1937
|
+
style: {
|
|
1938
|
+
width: toCssLength(width),
|
|
1939
|
+
height: toCssLength(height),
|
|
1940
|
+
borderRadius: toCssLength(radius),
|
|
1941
|
+
...style
|
|
1942
|
+
},
|
|
1943
|
+
...props
|
|
1944
|
+
}
|
|
1945
|
+
);
|
|
1946
|
+
}
|
|
1947
|
+
function GhostLine({ className, size = "md", width = "100%", ...props }) {
|
|
1948
|
+
return /* @__PURE__ */ jsx24(Ghost, { className: cn("fractal-ghost-line", `fractal-ghost-line--${size}`, className), width, ...props });
|
|
1949
|
+
}
|
|
1950
|
+
function ButtonGhost({ className, size = "md", iconOnly = false, width, ...props }) {
|
|
1951
|
+
return /* @__PURE__ */ jsx24(Ghost, { className: cn("fractal-ghost-button", `fractal-ghost-button--${size}`, iconOnly && "fractal-ghost-button--icon-only", className), width, ...props });
|
|
1952
|
+
}
|
|
1953
|
+
function CardGhost({ className, lines = 3, showHeader = true, ...props }) {
|
|
1954
|
+
return /* @__PURE__ */ jsxs20("div", { "aria-hidden": "true", className: cn("fractal-ghost-card", className), ...props, children: [
|
|
1955
|
+
showHeader && /* @__PURE__ */ jsx24(GhostLine, { width: "38%" }),
|
|
1956
|
+
/* @__PURE__ */ jsx24("div", { className: "fractal-ghost-stack", children: Array.from({ length: lines }, (_, index) => /* @__PURE__ */ jsx24(GhostLine, { width: index === lines - 1 ? "62%" : "100%" }, index)) })
|
|
1957
|
+
] });
|
|
1958
|
+
}
|
|
1959
|
+
function DataTableGhost({
|
|
1960
|
+
className,
|
|
1961
|
+
showHeader = true,
|
|
1962
|
+
headers,
|
|
1963
|
+
columns = 4,
|
|
1964
|
+
rows = 5,
|
|
1965
|
+
columnWidths,
|
|
1966
|
+
size = "md",
|
|
1967
|
+
...props
|
|
1968
|
+
}) {
|
|
1969
|
+
const cells = Array.from({ length: columns }, (_, index) => index);
|
|
1970
|
+
return /* @__PURE__ */ jsx24("div", { "aria-busy": "true", "aria-label": "Loading table", className: cn("fractal-ghost-table", `fractal-ghost-table--${size}`, className), role: "status", ...props, children: /* @__PURE__ */ jsxs20("table", { className: "fractal-ghost-table__table", children: [
|
|
1971
|
+
(showHeader || headers) && /* @__PURE__ */ jsx24("thead", { children: /* @__PURE__ */ jsx24("tr", { className: "fractal-ghost-table__head-row", children: cells.map((index) => /* @__PURE__ */ jsx24("th", { style: { width: columnWidths?.[index] }, children: headers?.[index] ?? /* @__PURE__ */ jsx24(GhostLine, { size: "sm", width: index === columns - 1 ? "62%" : "76%" }) }, index)) }) }),
|
|
1972
|
+
/* @__PURE__ */ jsx24("tbody", { children: Array.from({ length: rows }, (_, rowIndex) => /* @__PURE__ */ jsx24("tr", { className: "fractal-ghost-table__row", children: cells.map((columnIndex) => /* @__PURE__ */ jsx24("td", { style: { width: columnWidths?.[columnIndex] }, children: /* @__PURE__ */ jsx24(GhostLine, { width: `${[72, 54, 82, 63, 46][(rowIndex + columnIndex) % 5]}%` }) }, columnIndex)) }, rowIndex)) })
|
|
1973
|
+
] }) });
|
|
1974
|
+
}
|
|
1975
|
+
function InputGhost({ className, labelWidth = "26%", ...props }) {
|
|
1976
|
+
return /* @__PURE__ */ jsx24(FormFieldGhost, { className, labelWidth, ...props });
|
|
1977
|
+
}
|
|
1978
|
+
function TextareaGhost({ className, labelWidth = "26%", ...props }) {
|
|
1979
|
+
return /* @__PURE__ */ jsx24(FormFieldGhost, { className, labelWidth, multiline: true, ...props });
|
|
1980
|
+
}
|
|
1981
|
+
function LabelGhost({ className, width = "26%", ...props }) {
|
|
1982
|
+
return /* @__PURE__ */ jsx24(GhostLine, { className: cn("fractal-ghost-label", className), size: "sm", width, ...props });
|
|
1983
|
+
}
|
|
1984
|
+
function FormFieldGhost({ className, labelWidth = "26%", multiline = false, ...props }) {
|
|
1985
|
+
return /* @__PURE__ */ jsxs20("div", { "aria-hidden": "true", className: cn("fractal-ghost-field", className), ...props, children: [
|
|
1986
|
+
/* @__PURE__ */ jsx24(LabelGhost, { width: labelWidth }),
|
|
1987
|
+
/* @__PURE__ */ jsx24(Ghost, { className: cn("fractal-ghost-field__control", multiline && "fractal-ghost-field__control--multiline") })
|
|
1988
|
+
] });
|
|
1989
|
+
}
|
|
1990
|
+
function AlertGhost({ className, ...props }) {
|
|
1991
|
+
return /* @__PURE__ */ jsxs20("div", { "aria-hidden": "true", className: cn("fractal-ghost-alert", className), ...props, children: [
|
|
1992
|
+
/* @__PURE__ */ jsx24(GhostLine, { width: "30%" }),
|
|
1993
|
+
/* @__PURE__ */ jsx24(GhostLine, { size: "sm", width: "78%" })
|
|
1994
|
+
] });
|
|
1995
|
+
}
|
|
1996
|
+
function CheckboxGhost({ className, ...props }) {
|
|
1997
|
+
return /* @__PURE__ */ jsxs20("div", { "aria-hidden": "true", className: cn("fractal-ghost-choice", className), ...props, children: [
|
|
1998
|
+
/* @__PURE__ */ jsx24(Ghost, { className: "fractal-ghost-choice__control" }),
|
|
1999
|
+
/* @__PURE__ */ jsx24(GhostLine, { width: "42%" })
|
|
2000
|
+
] });
|
|
2001
|
+
}
|
|
2002
|
+
var ToggleGhost = CheckboxGhost;
|
|
2003
|
+
function ChipGhost({ className, width = 74, ...props }) {
|
|
2004
|
+
return /* @__PURE__ */ jsx24(Ghost, { className: cn("fractal-ghost-chip", className), height: 24, width, ...props });
|
|
2005
|
+
}
|
|
2006
|
+
function LinkGhost({ className, width = 96, ...props }) {
|
|
2007
|
+
return /* @__PURE__ */ jsx24(GhostLine, { className: cn("fractal-ghost-link", className), size: "sm", width, ...props });
|
|
2008
|
+
}
|
|
2009
|
+
var TextButtonGhost = LinkGhost;
|
|
2010
|
+
function DropdownGhost({ className, ...props }) {
|
|
2011
|
+
return /* @__PURE__ */ jsxs20("div", { "aria-hidden": "true", className: cn("fractal-ghost-dropdown", className), ...props, children: [
|
|
2012
|
+
/* @__PURE__ */ jsx24(GhostLine, { width: "38%" }),
|
|
2013
|
+
/* @__PURE__ */ jsx24(Ghost, { className: "fractal-ghost-dropdown__chevron" })
|
|
2014
|
+
] });
|
|
2015
|
+
}
|
|
2016
|
+
function ContentSwitcherGhost({ className, options = 3, ...props }) {
|
|
2017
|
+
return /* @__PURE__ */ jsx24("div", { "aria-hidden": "true", className: cn("fractal-ghost-switcher", className), ...props, children: Array.from({ length: options }, (_, index) => /* @__PURE__ */ jsx24(Ghost, {}, index)) });
|
|
2018
|
+
}
|
|
2019
|
+
var TabsGhost = ContentSwitcherGhost;
|
|
2020
|
+
function DisclosureGhost({ className, ...props }) {
|
|
2021
|
+
return /* @__PURE__ */ jsxs20("div", { "aria-hidden": "true", className: cn("fractal-ghost-disclosure", className), ...props, children: [
|
|
2022
|
+
/* @__PURE__ */ jsx24(Ghost, { className: "fractal-ghost-disclosure__icon" }),
|
|
2023
|
+
/* @__PURE__ */ jsx24(GhostLine, { width: "42%" })
|
|
2024
|
+
] });
|
|
2025
|
+
}
|
|
2026
|
+
function PaginationGhost({ className, pages = 5, ...props }) {
|
|
2027
|
+
return /* @__PURE__ */ jsx24("div", { "aria-hidden": "true", className: cn("fractal-ghost-pagination", className), ...props, children: Array.from({ length: pages }, (_, index) => /* @__PURE__ */ jsx24(Ghost, {}, index)) });
|
|
2028
|
+
}
|
|
2029
|
+
function FileDropzoneGhost({ className, ...props }) {
|
|
2030
|
+
return /* @__PURE__ */ jsxs20("div", { "aria-hidden": "true", className: cn("fractal-ghost-dropzone", className), ...props, children: [
|
|
2031
|
+
/* @__PURE__ */ jsx24(Ghost, { className: "fractal-ghost-dropzone__icon" }),
|
|
2032
|
+
/* @__PURE__ */ jsx24(GhostLine, { width: "26%" }),
|
|
2033
|
+
/* @__PURE__ */ jsx24(GhostLine, { size: "sm", width: "46%" })
|
|
2034
|
+
] });
|
|
2035
|
+
}
|
|
2036
|
+
function PromptCardGhost({ className, ...props }) {
|
|
2037
|
+
return /* @__PURE__ */ jsx24(CardGhost, { className: cn("fractal-ghost-prompt-card", className), lines: 4, ...props });
|
|
2038
|
+
}
|
|
2039
|
+
function ConversationGhost({
|
|
2040
|
+
className,
|
|
2041
|
+
"aria-label": ariaLabel = "Loading conversation",
|
|
2042
|
+
...props
|
|
2043
|
+
}) {
|
|
2044
|
+
return /* @__PURE__ */ jsxs20(
|
|
2045
|
+
"div",
|
|
2046
|
+
{
|
|
2047
|
+
"aria-busy": "true",
|
|
2048
|
+
"aria-label": ariaLabel,
|
|
2049
|
+
className: cn("fractal-ghost-conversation", className),
|
|
2050
|
+
role: "status",
|
|
2051
|
+
...props,
|
|
2052
|
+
children: [
|
|
2053
|
+
/* @__PURE__ */ jsx24("div", { "aria-hidden": "true", className: "fractal-ghost-conversation__message fractal-ghost-conversation__message--user", children: /* @__PURE__ */ jsxs20("div", { className: "fractal-ghost-conversation__bubble", children: [
|
|
2054
|
+
/* @__PURE__ */ jsx24(GhostLine, { width: "100%" }),
|
|
2055
|
+
/* @__PURE__ */ jsx24(GhostLine, { width: "86%" }),
|
|
2056
|
+
/* @__PURE__ */ jsx24(GhostLine, { width: "64%" })
|
|
2057
|
+
] }) }),
|
|
2058
|
+
/* @__PURE__ */ jsxs20("div", { "aria-hidden": "true", className: "fractal-ghost-conversation__message fractal-ghost-conversation__message--assistant", children: [
|
|
2059
|
+
/* @__PURE__ */ jsx24(GhostLine, { width: "92%" }),
|
|
2060
|
+
/* @__PURE__ */ jsx24(GhostLine, { width: "78%" }),
|
|
2061
|
+
/* @__PURE__ */ jsx24(GhostLine, { width: "58%" })
|
|
2062
|
+
] })
|
|
2063
|
+
]
|
|
2064
|
+
}
|
|
2065
|
+
);
|
|
2066
|
+
}
|
|
2067
|
+
function SortableTableGhost(props) {
|
|
2068
|
+
return /* @__PURE__ */ jsx24(DataTableGhost, { ...props });
|
|
2069
|
+
}
|
|
2070
|
+
function SidebarGhost({ className, items = 6, ...props }) {
|
|
2071
|
+
return /* @__PURE__ */ jsxs20("aside", { "aria-hidden": "true", className: cn("fractal-ghost-sidebar", className), ...props, children: [
|
|
2072
|
+
/* @__PURE__ */ jsx24(Ghost, { className: "fractal-ghost-sidebar__brand" }),
|
|
2073
|
+
/* @__PURE__ */ jsx24("div", { className: "fractal-ghost-sidebar__items", children: Array.from({ length: items }, (_, index) => /* @__PURE__ */ jsxs20("div", { className: "fractal-ghost-sidebar__item", children: [
|
|
2074
|
+
/* @__PURE__ */ jsx24(Ghost, {}),
|
|
2075
|
+
/* @__PURE__ */ jsx24(GhostLine, { width: `${[54, 68, 44, 61][index % 4]}%` })
|
|
2076
|
+
] }, index)) })
|
|
2077
|
+
] });
|
|
2078
|
+
}
|
|
2079
|
+
function ModalGhost({ className, title, lines = 3, ...props }) {
|
|
2080
|
+
return /* @__PURE__ */ jsx24(SurfaceGhost, { className: cn("fractal-ghost-modal", className), title, lines, ...props });
|
|
2081
|
+
}
|
|
2082
|
+
function SidePanelGhost({ className, title, lines = 5, ...props }) {
|
|
2083
|
+
return /* @__PURE__ */ jsx24(SurfaceGhost, { className: cn("fractal-ghost-side-panel", className), title, lines, ...props });
|
|
2084
|
+
}
|
|
2085
|
+
function SurfaceGhost({ className, title, lines = 3, ...props }) {
|
|
2086
|
+
return /* @__PURE__ */ jsxs20("div", { "aria-hidden": "true", className: cn("fractal-ghost-surface", className), ...props, children: [
|
|
2087
|
+
/* @__PURE__ */ jsxs20("div", { className: "fractal-ghost-surface__header", children: [
|
|
2088
|
+
/* @__PURE__ */ jsx24(GhostLine, { width: "42%" }),
|
|
2089
|
+
/* @__PURE__ */ jsx24(Ghost, { className: "fractal-ghost-surface__close" })
|
|
2090
|
+
] }),
|
|
2091
|
+
title && /* @__PURE__ */ jsx24("div", { className: "fractal-ghost-surface__title", children: title }),
|
|
2092
|
+
/* @__PURE__ */ jsx24("div", { className: "fractal-ghost-stack", children: Array.from({ length: lines }, (_, index) => /* @__PURE__ */ jsx24(GhostLine, { width: index === lines - 1 ? "64%" : "100%" }, index)) })
|
|
2093
|
+
] });
|
|
2094
|
+
}
|
|
2095
|
+
|
|
987
2096
|
// src/components/Sidebar/Sidebar.tsx
|
|
988
|
-
import * as
|
|
989
|
-
import { jsx as
|
|
990
|
-
var Sidebar =
|
|
991
|
-
({ className, width, style, ...props }, ref) => /* @__PURE__ */
|
|
2097
|
+
import * as React15 from "react";
|
|
2098
|
+
import { Fragment as Fragment3, jsx as jsx25, jsxs as jsxs21 } from "react/jsx-runtime";
|
|
2099
|
+
var Sidebar = React15.forwardRef(
|
|
2100
|
+
({ className, width, compact = false, style, ...props }, ref) => /* @__PURE__ */ jsx25(
|
|
992
2101
|
"aside",
|
|
993
2102
|
{
|
|
994
2103
|
ref,
|
|
995
2104
|
className: cn("fractal-sidebar", className),
|
|
2105
|
+
"data-compact": compact || void 0,
|
|
996
2106
|
style: { ...style, ...width ? { "--fractal-sidebar-width": width } : {} },
|
|
997
2107
|
...props
|
|
998
2108
|
}
|
|
999
2109
|
)
|
|
1000
2110
|
);
|
|
1001
2111
|
Sidebar.displayName = "Sidebar";
|
|
1002
|
-
var SidebarHeader =
|
|
1003
|
-
({ className, ...props }, ref) => /* @__PURE__ */
|
|
2112
|
+
var SidebarHeader = React15.forwardRef(
|
|
2113
|
+
({ className, ...props }, ref) => /* @__PURE__ */ jsx25("div", { ref, className: cn("fractal-sidebar__header", className), ...props })
|
|
1004
2114
|
);
|
|
1005
2115
|
SidebarHeader.displayName = "SidebarHeader";
|
|
1006
|
-
var SidebarBrand =
|
|
1007
|
-
({ className, type = "button", ...props }, ref) => /* @__PURE__ */
|
|
2116
|
+
var SidebarBrand = React15.forwardRef(
|
|
2117
|
+
({ className, type = "button", ...props }, ref) => /* @__PURE__ */ jsx25("button", { ref, type, className: cn("fractal-sidebar__brand", className), ...props })
|
|
1008
2118
|
);
|
|
1009
2119
|
SidebarBrand.displayName = "SidebarBrand";
|
|
1010
|
-
|
|
1011
|
-
|
|
2120
|
+
function SidebarAccountMenu({
|
|
2121
|
+
name,
|
|
2122
|
+
items,
|
|
2123
|
+
onSelect,
|
|
2124
|
+
triggerLabel = "Account menu",
|
|
2125
|
+
icon,
|
|
2126
|
+
className
|
|
2127
|
+
}) {
|
|
2128
|
+
return /* @__PURE__ */ jsx25(
|
|
2129
|
+
Dropdown,
|
|
2130
|
+
{
|
|
2131
|
+
align: "left",
|
|
2132
|
+
className: cn("fractal-sidebar__account", className),
|
|
2133
|
+
items,
|
|
2134
|
+
onSelect,
|
|
2135
|
+
panelClassName: "fractal-sidebar__account-panel",
|
|
2136
|
+
selectedValue: "",
|
|
2137
|
+
triggerClassName: "fractal-sidebar__account-trigger",
|
|
2138
|
+
triggerContent: /* @__PURE__ */ jsxs21(Fragment3, { children: [
|
|
2139
|
+
icon && /* @__PURE__ */ jsx25("span", { className: "fractal-sidebar__account-icon", "aria-hidden": "true", children: icon }),
|
|
2140
|
+
/* @__PURE__ */ jsx25("span", { className: "fractal-sidebar__account-name", children: name })
|
|
2141
|
+
] }),
|
|
2142
|
+
triggerLabel,
|
|
2143
|
+
triggerVariant: "tertiary"
|
|
2144
|
+
}
|
|
2145
|
+
);
|
|
2146
|
+
}
|
|
2147
|
+
var SidebarNav = React15.forwardRef(
|
|
2148
|
+
({ className, ...props }, ref) => /* @__PURE__ */ jsx25("nav", { ref, className: cn("fractal-sidebar__nav", className), ...props })
|
|
1012
2149
|
);
|
|
1013
2150
|
SidebarNav.displayName = "SidebarNav";
|
|
1014
|
-
var SidebarSection =
|
|
1015
|
-
({ className, ...props }, ref) => /* @__PURE__ */
|
|
2151
|
+
var SidebarSection = React15.forwardRef(
|
|
2152
|
+
({ className, ...props }, ref) => /* @__PURE__ */ jsx25("div", { ref, className: cn("fractal-sidebar__section", className), ...props })
|
|
1016
2153
|
);
|
|
1017
2154
|
SidebarSection.displayName = "SidebarSection";
|
|
1018
|
-
var SidebarNavItem =
|
|
1019
|
-
({ active = false, icon, endAdornment, className, type = "button", children, ...props }, ref) => /* @__PURE__ */
|
|
2155
|
+
var SidebarNavItem = React15.forwardRef(
|
|
2156
|
+
({ active = false, icon, endAdornment, className, type = "button", children, ...props }, ref) => /* @__PURE__ */ jsxs21(
|
|
1020
2157
|
"button",
|
|
1021
2158
|
{
|
|
1022
2159
|
ref,
|
|
@@ -1026,28 +2163,28 @@ var SidebarNavItem = React10.forwardRef(
|
|
|
1026
2163
|
"aria-current": active ? "page" : void 0,
|
|
1027
2164
|
...props,
|
|
1028
2165
|
children: [
|
|
1029
|
-
icon && /* @__PURE__ */
|
|
1030
|
-
/* @__PURE__ */
|
|
1031
|
-
endAdornment && /* @__PURE__ */
|
|
2166
|
+
icon && /* @__PURE__ */ jsx25("span", { className: "fractal-sidebar__nav-item-icon", "aria-hidden": "true", children: icon }),
|
|
2167
|
+
/* @__PURE__ */ jsx25("span", { className: "fractal-sidebar__nav-item-label", children }),
|
|
2168
|
+
endAdornment && /* @__PURE__ */ jsx25("span", { className: "fractal-sidebar__nav-item-end", children: endAdornment })
|
|
1032
2169
|
]
|
|
1033
2170
|
}
|
|
1034
2171
|
)
|
|
1035
2172
|
);
|
|
1036
2173
|
SidebarNavItem.displayName = "SidebarNavItem";
|
|
1037
|
-
var SidebarFooter =
|
|
1038
|
-
({ className, ...props }, ref) => /* @__PURE__ */
|
|
2174
|
+
var SidebarFooter = React15.forwardRef(
|
|
2175
|
+
({ className, ...props }, ref) => /* @__PURE__ */ jsx25("div", { ref, className: cn("fractal-sidebar__footer", className), ...props })
|
|
1039
2176
|
);
|
|
1040
2177
|
SidebarFooter.displayName = "SidebarFooter";
|
|
1041
2178
|
|
|
1042
2179
|
// src/components/SidePanel/SidePanel.tsx
|
|
1043
2180
|
import { createPortal as createPortal2 } from "react-dom";
|
|
1044
2181
|
import { Close } from "@mirror-physics/fractal-icons";
|
|
1045
|
-
import { jsx as
|
|
1046
|
-
function SidePanel({ open, onClose, title, description, children, footer, size = "md", className }) {
|
|
2182
|
+
import { jsx as jsx26, jsxs as jsxs22 } from "react/jsx-runtime";
|
|
2183
|
+
function SidePanel({ open, onClose, title, description, children, footer, size = "md", loading = false, loadingLabel = "Loading", className }) {
|
|
1047
2184
|
useEscapeDismiss(80, onClose, open);
|
|
1048
2185
|
if (!open) return null;
|
|
1049
2186
|
return createPortal2(
|
|
1050
|
-
/* @__PURE__ */
|
|
2187
|
+
/* @__PURE__ */ jsx26("div", { className: "fractal-side-panel-overlay", onMouseDown: onClose, children: /* @__PURE__ */ jsxs22(
|
|
1051
2188
|
"aside",
|
|
1052
2189
|
{
|
|
1053
2190
|
className: cn("fractal-side-panel", `fractal-side-panel--${size}`, className),
|
|
@@ -1056,15 +2193,15 @@ function SidePanel({ open, onClose, title, description, children, footer, size =
|
|
|
1056
2193
|
role: "dialog",
|
|
1057
2194
|
onMouseDown: (event) => event.stopPropagation(),
|
|
1058
2195
|
children: [
|
|
1059
|
-
/* @__PURE__ */
|
|
1060
|
-
/* @__PURE__ */
|
|
1061
|
-
/* @__PURE__ */
|
|
1062
|
-
description && /* @__PURE__ */
|
|
2196
|
+
/* @__PURE__ */ jsxs22("header", { className: "fractal-side-panel__header", children: [
|
|
2197
|
+
/* @__PURE__ */ jsxs22("div", { className: "fractal-side-panel__heading", children: [
|
|
2198
|
+
typeof title === "string" ? /* @__PURE__ */ jsx26("h2", { className: "fractal-side-panel__title", children: title }) : /* @__PURE__ */ jsx26("div", { className: "fractal-side-panel__title", children: title }),
|
|
2199
|
+
description && /* @__PURE__ */ jsx26("p", { className: "fractal-side-panel__description", children: description })
|
|
1063
2200
|
] }),
|
|
1064
|
-
/* @__PURE__ */
|
|
2201
|
+
/* @__PURE__ */ jsx26("button", { type: "button", className: "fractal-side-panel__close", "aria-label": "Close panel", onClick: onClose, children: /* @__PURE__ */ jsx26(Close, { size: 18 }) })
|
|
1065
2202
|
] }),
|
|
1066
|
-
/* @__PURE__ */
|
|
1067
|
-
footer && /* @__PURE__ */
|
|
2203
|
+
/* @__PURE__ */ jsx26("div", { "aria-busy": loading || void 0, className: cn("fractal-side-panel__body", loading && "fractal-side-panel__body--loading"), children: loading ? /* @__PURE__ */ jsx26(UILoader, { label: loadingLabel }) : children }),
|
|
2204
|
+
footer && /* @__PURE__ */ jsx26("footer", { className: "fractal-side-panel__footer", children: footer })
|
|
1068
2205
|
]
|
|
1069
2206
|
}
|
|
1070
2207
|
) }),
|
|
@@ -1073,47 +2210,272 @@ function SidePanel({ open, onClose, title, description, children, footer, size =
|
|
|
1073
2210
|
}
|
|
1074
2211
|
|
|
1075
2212
|
// src/components/Textarea/Textarea.tsx
|
|
1076
|
-
import * as
|
|
1077
|
-
import { jsx as
|
|
1078
|
-
var Textarea =
|
|
1079
|
-
({ className, ...props }, ref) => /* @__PURE__ */
|
|
2213
|
+
import * as React16 from "react";
|
|
2214
|
+
import { jsx as jsx27 } from "react/jsx-runtime";
|
|
2215
|
+
var Textarea = React16.forwardRef(
|
|
2216
|
+
({ className, ...props }, ref) => /* @__PURE__ */ jsx27("textarea", { ref, className: cn("fractal-textarea", className), ...props })
|
|
1080
2217
|
);
|
|
1081
2218
|
Textarea.displayName = "Textarea";
|
|
2219
|
+
|
|
2220
|
+
// src/components/TextButton/TextButton.tsx
|
|
2221
|
+
import * as React17 from "react";
|
|
2222
|
+
import { jsx as jsx28, jsxs as jsxs23 } from "react/jsx-runtime";
|
|
2223
|
+
var TextButton = React17.forwardRef(
|
|
2224
|
+
({ className, icon, iconPosition = "start", size = "md", tone = "primary", children, ...props }, ref) => /* @__PURE__ */ jsxs23(
|
|
2225
|
+
"button",
|
|
2226
|
+
{
|
|
2227
|
+
ref,
|
|
2228
|
+
className: cn("fractal-text-button", `fractal-text-button--${size}`, `fractal-text-button--${tone}`, className),
|
|
2229
|
+
type: "button",
|
|
2230
|
+
...props,
|
|
2231
|
+
children: [
|
|
2232
|
+
icon && iconPosition === "start" && /* @__PURE__ */ jsx28("span", { className: "fractal-text-button__icon", "aria-hidden": "true", children: icon }),
|
|
2233
|
+
/* @__PURE__ */ jsx28("span", { children }),
|
|
2234
|
+
icon && iconPosition === "end" && /* @__PURE__ */ jsx28("span", { className: "fractal-text-button__icon", "aria-hidden": "true", children: icon })
|
|
2235
|
+
]
|
|
2236
|
+
}
|
|
2237
|
+
)
|
|
2238
|
+
);
|
|
2239
|
+
TextButton.displayName = "TextButton";
|
|
2240
|
+
|
|
2241
|
+
// src/components/FileDropzone/FileDropzone.tsx
|
|
2242
|
+
import * as React18 from "react";
|
|
2243
|
+
import { Close as Close2, FileArrowUp } from "@mirror-physics/fractal-icons";
|
|
2244
|
+
import { jsx as jsx29, jsxs as jsxs24 } from "react/jsx-runtime";
|
|
2245
|
+
function FileDropzone({
|
|
2246
|
+
files,
|
|
2247
|
+
onFilesChange,
|
|
2248
|
+
accept,
|
|
2249
|
+
multiple = true,
|
|
2250
|
+
disabled = false,
|
|
2251
|
+
title = "Drop files here or click to browse",
|
|
2252
|
+
description = "Files stay attached to this record.",
|
|
2253
|
+
className
|
|
2254
|
+
}) {
|
|
2255
|
+
const inputId = React18.useId();
|
|
2256
|
+
const inputRef = React18.useRef(null);
|
|
2257
|
+
const [isDragging, setIsDragging] = React18.useState(false);
|
|
2258
|
+
const addFiles = (nextFiles) => {
|
|
2259
|
+
if (disabled) return;
|
|
2260
|
+
const additions = Array.from(nextFiles);
|
|
2261
|
+
if (additions.length === 0) return;
|
|
2262
|
+
onFilesChange(multiple ? [...files, ...additions] : additions.slice(0, 1));
|
|
2263
|
+
};
|
|
2264
|
+
return /* @__PURE__ */ jsxs24("div", { className: cn("fractal-file-dropzone", className), children: [
|
|
2265
|
+
/* @__PURE__ */ jsx29(
|
|
2266
|
+
"input",
|
|
2267
|
+
{
|
|
2268
|
+
ref: inputRef,
|
|
2269
|
+
id: inputId,
|
|
2270
|
+
className: "fractal-file-dropzone__input",
|
|
2271
|
+
type: "file",
|
|
2272
|
+
accept,
|
|
2273
|
+
multiple,
|
|
2274
|
+
disabled,
|
|
2275
|
+
onChange: (event) => {
|
|
2276
|
+
if (event.target.files) addFiles(event.target.files);
|
|
2277
|
+
event.target.value = "";
|
|
2278
|
+
}
|
|
2279
|
+
}
|
|
2280
|
+
),
|
|
2281
|
+
/* @__PURE__ */ jsxs24(
|
|
2282
|
+
"button",
|
|
2283
|
+
{
|
|
2284
|
+
className: "fractal-file-dropzone__target",
|
|
2285
|
+
"data-dragging": isDragging || void 0,
|
|
2286
|
+
type: "button",
|
|
2287
|
+
disabled,
|
|
2288
|
+
onClick: () => inputRef.current?.click(),
|
|
2289
|
+
onDragEnter: (event) => {
|
|
2290
|
+
event.preventDefault();
|
|
2291
|
+
if (!disabled) setIsDragging(true);
|
|
2292
|
+
},
|
|
2293
|
+
onDragOver: (event) => event.preventDefault(),
|
|
2294
|
+
onDragLeave: (event) => {
|
|
2295
|
+
event.preventDefault();
|
|
2296
|
+
setIsDragging(false);
|
|
2297
|
+
},
|
|
2298
|
+
onDrop: (event) => {
|
|
2299
|
+
event.preventDefault();
|
|
2300
|
+
setIsDragging(false);
|
|
2301
|
+
addFiles(event.dataTransfer.files);
|
|
2302
|
+
},
|
|
2303
|
+
children: [
|
|
2304
|
+
/* @__PURE__ */ jsx29(FileArrowUp, { "aria-hidden": "true", size: 20 }),
|
|
2305
|
+
/* @__PURE__ */ jsxs24("span", { className: "fractal-file-dropzone__copy", children: [
|
|
2306
|
+
/* @__PURE__ */ jsx29("span", { className: "fractal-file-dropzone__title", children: title }),
|
|
2307
|
+
description && /* @__PURE__ */ jsx29("span", { className: "fractal-file-dropzone__description", children: description })
|
|
2308
|
+
] })
|
|
2309
|
+
]
|
|
2310
|
+
}
|
|
2311
|
+
),
|
|
2312
|
+
files.length > 0 && /* @__PURE__ */ jsx29("ul", { className: "fractal-file-dropzone__files", "aria-label": "Attached files", children: files.map((file, index) => /* @__PURE__ */ jsxs24("li", { className: "fractal-file-dropzone__file", children: [
|
|
2313
|
+
/* @__PURE__ */ jsx29("span", { className: "fractal-file-dropzone__file-name", children: file.name }),
|
|
2314
|
+
/* @__PURE__ */ jsx29("span", { className: "fractal-file-dropzone__file-meta", children: formatFileSize(file.size) }),
|
|
2315
|
+
/* @__PURE__ */ jsx29(
|
|
2316
|
+
"button",
|
|
2317
|
+
{
|
|
2318
|
+
className: "fractal-file-dropzone__remove",
|
|
2319
|
+
type: "button",
|
|
2320
|
+
"aria-label": `Remove ${file.name}`,
|
|
2321
|
+
disabled,
|
|
2322
|
+
onClick: () => onFilesChange(files.filter((_, fileIndex) => fileIndex !== index)),
|
|
2323
|
+
children: /* @__PURE__ */ jsx29(Close2, { "aria-hidden": "true", size: 14 })
|
|
2324
|
+
}
|
|
2325
|
+
)
|
|
2326
|
+
] }, `${file.name}-${file.size}-${index}`)) })
|
|
2327
|
+
] });
|
|
2328
|
+
}
|
|
2329
|
+
function formatFileSize(bytes) {
|
|
2330
|
+
if (bytes < 1024) return `${bytes} B`;
|
|
2331
|
+
if (bytes < 1024 * 1024) return `${Math.round(bytes / 1024)} KB`;
|
|
2332
|
+
return `${(bytes / (1024 * 1024)).toFixed(1)} MB`;
|
|
2333
|
+
}
|
|
2334
|
+
|
|
2335
|
+
// src/components/Pagination/Pagination.tsx
|
|
2336
|
+
import { ArrowLeft, ArrowRight } from "@mirror-physics/fractal-icons";
|
|
2337
|
+
import { jsx as jsx30, jsxs as jsxs25 } from "react/jsx-runtime";
|
|
2338
|
+
function Pagination({
|
|
2339
|
+
page,
|
|
2340
|
+
pageSize,
|
|
2341
|
+
totalItems,
|
|
2342
|
+
onPageChange,
|
|
2343
|
+
pageSizeOptions,
|
|
2344
|
+
onPageSizeChange,
|
|
2345
|
+
ariaLabel = "Pagination",
|
|
2346
|
+
className
|
|
2347
|
+
}) {
|
|
2348
|
+
const totalPages = Math.max(1, Math.ceil(totalItems / pageSize));
|
|
2349
|
+
const currentPage = Math.min(Math.max(page, 1), totalPages);
|
|
2350
|
+
const start = totalItems === 0 ? 0 : (currentPage - 1) * pageSize + 1;
|
|
2351
|
+
const end = Math.min(currentPage * pageSize, totalItems);
|
|
2352
|
+
const canChangePageSize = pageSizeOptions != null && pageSizeOptions.length > 0 && onPageSizeChange != null;
|
|
2353
|
+
return /* @__PURE__ */ jsxs25("nav", { className: cn("fractal-pagination", className), "aria-label": ariaLabel, children: [
|
|
2354
|
+
/* @__PURE__ */ jsx30("span", { className: "fractal-pagination__summary", children: totalItems === 0 ? "No results" : `${start}-${end} of ${totalItems}` }),
|
|
2355
|
+
/* @__PURE__ */ jsxs25("div", { className: "fractal-pagination__controls", children: [
|
|
2356
|
+
canChangePageSize && /* @__PURE__ */ jsx30(
|
|
2357
|
+
Dropdown,
|
|
2358
|
+
{
|
|
2359
|
+
align: "right",
|
|
2360
|
+
className: "fractal-pagination__page-size",
|
|
2361
|
+
direction: "up",
|
|
2362
|
+
items: pageSizeOptions.map((option) => ({
|
|
2363
|
+
value: String(option),
|
|
2364
|
+
description: `${option} per page`
|
|
2365
|
+
})),
|
|
2366
|
+
onSelect: (value) => onPageSizeChange(Number(value)),
|
|
2367
|
+
selectedValue: String(pageSize),
|
|
2368
|
+
size: "sm",
|
|
2369
|
+
triggerLabel: "Results per page",
|
|
2370
|
+
triggerVariant: "tertiary"
|
|
2371
|
+
}
|
|
2372
|
+
),
|
|
2373
|
+
/* @__PURE__ */ jsx30(
|
|
2374
|
+
"button",
|
|
2375
|
+
{
|
|
2376
|
+
className: "fractal-pagination__button",
|
|
2377
|
+
type: "button",
|
|
2378
|
+
"aria-label": "Previous page",
|
|
2379
|
+
title: "Previous page",
|
|
2380
|
+
disabled: currentPage === 1 || totalItems === 0,
|
|
2381
|
+
onClick: () => onPageChange(currentPage - 1),
|
|
2382
|
+
children: /* @__PURE__ */ jsx30(ArrowLeft, { "aria-hidden": "true", size: 16 })
|
|
2383
|
+
}
|
|
2384
|
+
),
|
|
2385
|
+
/* @__PURE__ */ jsxs25("span", { className: "fractal-pagination__page", "aria-current": "page", children: [
|
|
2386
|
+
currentPage,
|
|
2387
|
+
" of ",
|
|
2388
|
+
totalPages
|
|
2389
|
+
] }),
|
|
2390
|
+
/* @__PURE__ */ jsx30(
|
|
2391
|
+
"button",
|
|
2392
|
+
{
|
|
2393
|
+
className: "fractal-pagination__button",
|
|
2394
|
+
type: "button",
|
|
2395
|
+
"aria-label": "Next page",
|
|
2396
|
+
title: "Next page",
|
|
2397
|
+
disabled: currentPage === totalPages || totalItems === 0,
|
|
2398
|
+
onClick: () => onPageChange(currentPage + 1),
|
|
2399
|
+
children: /* @__PURE__ */ jsx30(ArrowRight, { "aria-hidden": "true", size: 16 })
|
|
2400
|
+
}
|
|
2401
|
+
)
|
|
2402
|
+
] })
|
|
2403
|
+
] });
|
|
2404
|
+
}
|
|
1082
2405
|
export {
|
|
1083
2406
|
Alert,
|
|
1084
2407
|
AlertDescription,
|
|
2408
|
+
AlertGhost,
|
|
1085
2409
|
AlertTitle,
|
|
2410
|
+
Breadcrumbs,
|
|
1086
2411
|
Button,
|
|
2412
|
+
ButtonGhost,
|
|
1087
2413
|
Card,
|
|
1088
2414
|
CardContent,
|
|
1089
2415
|
CardDescription,
|
|
1090
2416
|
CardFooter,
|
|
2417
|
+
CardGhost,
|
|
1091
2418
|
CardHeader,
|
|
1092
2419
|
CardTitle,
|
|
2420
|
+
Checkbox,
|
|
2421
|
+
CheckboxGhost,
|
|
1093
2422
|
Chip,
|
|
2423
|
+
ChipGhost,
|
|
2424
|
+
CodeBlock,
|
|
2425
|
+
ContentSwitcher,
|
|
2426
|
+
ContentSwitcherGhost,
|
|
2427
|
+
ConversationGhost,
|
|
1094
2428
|
DataTable,
|
|
2429
|
+
DataTableGhost,
|
|
1095
2430
|
Disclosure,
|
|
2431
|
+
DisclosureGhost,
|
|
1096
2432
|
Dropdown,
|
|
2433
|
+
DropdownGhost,
|
|
1097
2434
|
FeatureCard,
|
|
2435
|
+
FileDropzone,
|
|
2436
|
+
FileDropzoneGhost,
|
|
1098
2437
|
FolderCard,
|
|
2438
|
+
Ghost,
|
|
2439
|
+
GhostLine,
|
|
1099
2440
|
Input,
|
|
2441
|
+
InputGhost,
|
|
1100
2442
|
Label,
|
|
2443
|
+
LabelGhost,
|
|
2444
|
+
LatticeLoader,
|
|
1101
2445
|
Link,
|
|
2446
|
+
LinkGhost,
|
|
1102
2447
|
Modal,
|
|
2448
|
+
ModalGhost,
|
|
2449
|
+
NumberInput,
|
|
2450
|
+
Pagination,
|
|
2451
|
+
PaginationGhost,
|
|
2452
|
+
PasswordInput,
|
|
1103
2453
|
PromptCard,
|
|
2454
|
+
PromptCardGhost,
|
|
1104
2455
|
PromptGrid,
|
|
1105
2456
|
SidePanel,
|
|
2457
|
+
SidePanelGhost,
|
|
1106
2458
|
Sidebar,
|
|
2459
|
+
SidebarAccountMenu,
|
|
1107
2460
|
SidebarBrand,
|
|
1108
2461
|
SidebarFooter,
|
|
2462
|
+
SidebarGhost,
|
|
1109
2463
|
SidebarHeader,
|
|
1110
2464
|
SidebarNav,
|
|
1111
2465
|
SidebarNavItem,
|
|
1112
2466
|
SidebarSection,
|
|
1113
2467
|
SortableTable,
|
|
2468
|
+
SortableTableGhost,
|
|
2469
|
+
TableSearch,
|
|
1114
2470
|
Tabs,
|
|
2471
|
+
TabsGhost,
|
|
2472
|
+
TextButton,
|
|
2473
|
+
TextButtonGhost,
|
|
1115
2474
|
Textarea,
|
|
2475
|
+
TextareaGhost,
|
|
1116
2476
|
Toggle,
|
|
2477
|
+
ToggleGhost,
|
|
2478
|
+
UILoader,
|
|
1117
2479
|
cn,
|
|
1118
2480
|
useEscapeDismiss
|
|
1119
2481
|
};
|