@ai-matrx/design-system 0.86.349 → 0.86.351
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/CHANGELOG.md +22 -2
- package/dist/carousel.cjs.map +1 -1
- package/dist/carousel.js +5 -5
- package/dist/chunk-4WSXAP24.js +51 -0
- package/dist/chunk-4WSXAP24.js.map +1 -0
- package/dist/{chunk-XTP6HOB6.js → chunk-6XNYYROM.js} +1 -1
- package/dist/chunk-6XNYYROM.js.map +1 -0
- package/dist/{chunk-CEA6X445.js → chunk-CFUXEGW2.js} +2 -2
- package/dist/{chunk-54UK6P7E.js → chunk-FLWSEDUW.js} +3 -3
- package/dist/{chunk-BC7LMEOD.js → chunk-GJ6UGQ4X.js} +7 -3
- package/dist/chunk-GJ6UGQ4X.js.map +1 -0
- package/dist/{chunk-6CDAHINE.js → chunk-GMNROZQJ.js} +4 -4
- package/dist/{chunk-6CDAHINE.js.map → chunk-GMNROZQJ.js.map} +1 -1
- package/dist/{chunk-6QKT52FR.js → chunk-MTE6N7XU.js} +2 -2
- package/dist/{chunk-S6F34AX5.js → chunk-QA7EHFRX.js} +2 -2
- package/dist/{chunk-CJBSBKG5.js → chunk-SOCNWQMX.js} +2 -2
- package/dist/{chunk-GLLPO66A.js → chunk-U46XUQI7.js} +2 -2
- package/dist/{chunk-KYH42WEX.js → chunk-UGQRAQTE.js} +433 -344
- package/dist/chunk-UGQRAQTE.js.map +1 -0
- package/dist/{chunk-TWRC7NP4.js → chunk-WUD23YTG.js} +4 -4
- package/dist/{chunk-MIJMP4WI.js → chunk-YRF22M5S.js} +6 -1
- package/dist/{chunk-MIJMP4WI.js.map → chunk-YRF22M5S.js.map} +1 -1
- package/dist/clipboard-fallback-dialog.cjs.map +1 -1
- package/dist/clipboard-fallback-dialog.js +1 -1
- package/dist/controls.cjs +547 -458
- package/dist/controls.cjs.map +1 -1
- package/dist/controls.css +52 -18
- package/dist/controls.d.cts +51 -3
- package/dist/controls.d.ts +51 -3
- package/dist/controls.js +13 -5
- package/dist/data-table/data-row-inspector.cjs.map +1 -1
- package/dist/data-table/data-row-inspector.js +4 -4
- package/dist/data-table/data-row-window.cjs.map +1 -1
- package/dist/data-table/data-row-window.js +5 -5
- package/dist/data-table/index.cjs +53 -43
- package/dist/data-table/index.cjs.map +1 -1
- package/dist/data-table/index.js +52 -45
- package/dist/data-table/index.js.map +1 -1
- package/dist/data-table/pagination.cjs.map +1 -1
- package/dist/data-table/pagination.js +2 -2
- package/dist/data-table/spreadsheet.cjs +6 -2
- package/dist/data-table/spreadsheet.cjs.map +1 -1
- package/dist/data-table/spreadsheet.d.cts +4 -1
- package/dist/data-table/spreadsheet.d.ts +4 -1
- package/dist/data-table/spreadsheet.js +3 -1
- package/dist/data-table/uuid-cell.cjs.map +1 -1
- package/dist/data-table/uuid-cell.js +2 -2
- package/dist/desktop.cjs +158 -16
- package/dist/desktop.cjs.map +1 -1
- package/dist/desktop.css +46 -0
- package/dist/desktop.d.cts +6 -5
- package/dist/desktop.d.ts +6 -5
- package/dist/desktop.js +127 -17
- package/dist/desktop.js.map +1 -1
- package/dist/index.cjs +19 -9
- package/dist/index.cjs.map +1 -1
- package/dist/index.d.cts +10 -1
- package/dist/index.d.ts +10 -1
- package/dist/index.js +21 -14
- package/dist/index.js.map +1 -1
- package/dist/item.cjs.map +1 -1
- package/dist/item.js +2 -2
- package/dist/lite-table.cjs.map +1 -1
- package/dist/lite-table.js +1 -1
- package/dist/notice-stack.cjs +70 -0
- package/dist/notice-stack.cjs.map +1 -0
- package/dist/notice-stack.d.cts +60 -0
- package/dist/notice-stack.d.ts +60 -0
- package/dist/notice-stack.js +16 -0
- package/dist/notice-stack.js.map +1 -0
- package/dist/record-list.cjs.map +1 -1
- package/dist/record-list.js +2 -2
- package/dist/settings.cjs +2 -2
- package/dist/settings.cjs.map +1 -1
- package/dist/settings.js +3 -3
- package/dist/swipe-deck.cjs +95 -25
- package/dist/swipe-deck.cjs.map +1 -1
- package/dist/swipe-deck.css +14 -0
- package/dist/swipe-deck.d.cts +20 -0
- package/dist/swipe-deck.d.ts +20 -0
- package/dist/swipe-deck.js +87 -25
- package/dist/swipe-deck.js.map +1 -1
- package/dist/writing-field.cjs +2 -2
- package/dist/writing-field.cjs.map +1 -1
- package/dist/writing-field.js +2 -2
- package/package.json +12 -18
- package/dist/chunk-BC7LMEOD.js.map +0 -1
- package/dist/chunk-KYH42WEX.js.map +0 -1
- package/dist/chunk-XTP6HOB6.js.map +0 -1
- /package/dist/{chunk-CEA6X445.js.map → chunk-CFUXEGW2.js.map} +0 -0
- /package/dist/{chunk-54UK6P7E.js.map → chunk-FLWSEDUW.js.map} +0 -0
- /package/dist/{chunk-6QKT52FR.js.map → chunk-MTE6N7XU.js.map} +0 -0
- /package/dist/{chunk-S6F34AX5.js.map → chunk-QA7EHFRX.js.map} +0 -0
- /package/dist/{chunk-CJBSBKG5.js.map → chunk-SOCNWQMX.js.map} +0 -0
- /package/dist/{chunk-GLLPO66A.js.map → chunk-U46XUQI7.js.map} +0 -0
- /package/dist/{chunk-TWRC7NP4.js.map → chunk-WUD23YTG.js.map} +0 -0
package/dist/swipe-deck.css
CHANGED
|
@@ -547,6 +547,20 @@
|
|
|
547
547
|
.matrx-sd .matrx-sd-review-change { opacity: 1; }
|
|
548
548
|
}
|
|
549
549
|
.matrx-sd-end-actions { display: flex; flex-wrap: wrap; gap: 10px; margin-top: 24px; }
|
|
550
|
+
/* the answered list, mid-deck: no mark, its title and the way back */
|
|
551
|
+
.matrx-sd .matrx-sd-review-back {
|
|
552
|
+
margin: 0; height: 40px; padding: 0 18px; border: 0; border-radius: 20px;
|
|
553
|
+
background: hsl(var(--primary)); color: hsl(var(--primary-foreground));
|
|
554
|
+
font: inherit; font-size: 15px; font-weight: 600;
|
|
555
|
+
}
|
|
556
|
+
@media (hover: hover) { .matrx-sd .matrx-sd-review-back:hover { filter: brightness(1.06); } }
|
|
557
|
+
.matrx-sd .matrx-sd-corner { position: relative; }
|
|
558
|
+
.matrx-sd .matrx-sd-corner[aria-pressed="true"] { color: var(--sd-fg); background: var(--sd-pill); }
|
|
559
|
+
.matrx-sd-corner-count {
|
|
560
|
+
position: absolute; top: 2px; right: 0; min-width: 18px; height: 18px; padding: 0 5px; border-radius: 9px;
|
|
561
|
+
background: hsl(var(--primary)); color: hsl(var(--primary-foreground));
|
|
562
|
+
font-size: 11px; font-weight: 700; line-height: 18px; text-align: center; font-variant-numeric: tabular-nums;
|
|
563
|
+
}
|
|
550
564
|
/* Nothing to answer: three outline cards, fanned, and the words under them. */
|
|
551
565
|
.matrx-sd-empty { align-items: center; text-align: center; margin: auto; }
|
|
552
566
|
.matrx-sd-empty .matrx-sd-end-hero { font-size: clamp(28px, min(7vw, 9cqh), 56px); }
|
package/dist/swipe-deck.d.cts
CHANGED
|
@@ -22,6 +22,17 @@ interface DeckAnswer {
|
|
|
22
22
|
/** Stable id: what results, callbacks and connections carry. */
|
|
23
23
|
readonly id: string;
|
|
24
24
|
readonly label: string;
|
|
25
|
+
/**
|
|
26
|
+
* Offered only through the card's own controls (`renderCardActions` / `renderCardBody` call
|
|
27
|
+
* `answer(id)`), never drawn as a button: an answer that needs a choice first ("Related ▸ Partner").
|
|
28
|
+
*/
|
|
29
|
+
readonly hidden?: boolean;
|
|
30
|
+
/**
|
|
31
|
+
* "Skip for now": in a bound deck the connection moves the card to the back of the line and keeps no
|
|
32
|
+
* answer (it comes back once the rest are answered); undo brings it back to the front. In a deck with no
|
|
33
|
+
* connection it is kept like any other answer.
|
|
34
|
+
*/
|
|
35
|
+
readonly requeue?: boolean;
|
|
25
36
|
readonly tone: DeckTone;
|
|
26
37
|
/** Higher is better. Decides which answer wins when categories disagree (default by direction). */
|
|
27
38
|
readonly rank?: number;
|
|
@@ -289,6 +300,11 @@ interface DeckChange {
|
|
|
289
300
|
readonly ops: readonly DeckOp[];
|
|
290
301
|
readonly inverse: readonly DeckOp[];
|
|
291
302
|
readonly from: DeckDirection | null;
|
|
303
|
+
/**
|
|
304
|
+
* The connection acts on it but never keeps it as an answer (a `requeue` answer: the card goes to the
|
|
305
|
+
* back of the line): once the connection resolves, the deck stops drawing it, so the card is unanswered.
|
|
306
|
+
*/
|
|
307
|
+
readonly transient?: boolean;
|
|
292
308
|
}
|
|
293
309
|
declare function applyOp(state: DeckState, op: DeckOp): DeckState;
|
|
294
310
|
declare function applyOps(state: DeckState, ops: readonly DeckOp[]): DeckState;
|
|
@@ -437,6 +453,10 @@ interface SwipeDeckLabels {
|
|
|
437
453
|
readonly filterAnswers: string;
|
|
438
454
|
/** The empty screen (no items). */
|
|
439
455
|
readonly emptyTitle: string;
|
|
456
|
+
/** The corner that opens every answer so far, and that list's title. */
|
|
457
|
+
readonly answered: string;
|
|
458
|
+
/** Leave the answered list for the card in focus. */
|
|
459
|
+
readonly backToCards: string;
|
|
440
460
|
}
|
|
441
461
|
declare const DEFAULT_SWIPE_DECK_LABELS: SwipeDeckLabels;
|
|
442
462
|
|
package/dist/swipe-deck.d.ts
CHANGED
|
@@ -22,6 +22,17 @@ interface DeckAnswer {
|
|
|
22
22
|
/** Stable id: what results, callbacks and connections carry. */
|
|
23
23
|
readonly id: string;
|
|
24
24
|
readonly label: string;
|
|
25
|
+
/**
|
|
26
|
+
* Offered only through the card's own controls (`renderCardActions` / `renderCardBody` call
|
|
27
|
+
* `answer(id)`), never drawn as a button: an answer that needs a choice first ("Related ▸ Partner").
|
|
28
|
+
*/
|
|
29
|
+
readonly hidden?: boolean;
|
|
30
|
+
/**
|
|
31
|
+
* "Skip for now": in a bound deck the connection moves the card to the back of the line and keeps no
|
|
32
|
+
* answer (it comes back once the rest are answered); undo brings it back to the front. In a deck with no
|
|
33
|
+
* connection it is kept like any other answer.
|
|
34
|
+
*/
|
|
35
|
+
readonly requeue?: boolean;
|
|
25
36
|
readonly tone: DeckTone;
|
|
26
37
|
/** Higher is better. Decides which answer wins when categories disagree (default by direction). */
|
|
27
38
|
readonly rank?: number;
|
|
@@ -289,6 +300,11 @@ interface DeckChange {
|
|
|
289
300
|
readonly ops: readonly DeckOp[];
|
|
290
301
|
readonly inverse: readonly DeckOp[];
|
|
291
302
|
readonly from: DeckDirection | null;
|
|
303
|
+
/**
|
|
304
|
+
* The connection acts on it but never keeps it as an answer (a `requeue` answer: the card goes to the
|
|
305
|
+
* back of the line): once the connection resolves, the deck stops drawing it, so the card is unanswered.
|
|
306
|
+
*/
|
|
307
|
+
readonly transient?: boolean;
|
|
292
308
|
}
|
|
293
309
|
declare function applyOp(state: DeckState, op: DeckOp): DeckState;
|
|
294
310
|
declare function applyOps(state: DeckState, ops: readonly DeckOp[]): DeckState;
|
|
@@ -437,6 +453,10 @@ interface SwipeDeckLabels {
|
|
|
437
453
|
readonly filterAnswers: string;
|
|
438
454
|
/** The empty screen (no items). */
|
|
439
455
|
readonly emptyTitle: string;
|
|
456
|
+
/** The corner that opens every answer so far, and that list's title. */
|
|
457
|
+
readonly answered: string;
|
|
458
|
+
/** Leave the answered list for the card in focus. */
|
|
459
|
+
readonly backToCards: string;
|
|
440
460
|
}
|
|
441
461
|
declare const DEFAULT_SWIPE_DECK_LABELS: SwipeDeckLabels;
|
|
442
462
|
|
package/dist/swipe-deck.js
CHANGED
|
@@ -15,6 +15,7 @@ import {
|
|
|
15
15
|
CircleHelpIcon,
|
|
16
16
|
CopyIcon,
|
|
17
17
|
EraserIcon,
|
|
18
|
+
ListChecksIcon,
|
|
18
19
|
Loader2Icon,
|
|
19
20
|
Maximize2Icon,
|
|
20
21
|
Minimize2Icon,
|
|
@@ -213,7 +214,7 @@ function EdgeButtons({ keyMap, suggested, refs, onAnswer, suggestionLabel, disab
|
|
|
213
214
|
);
|
|
214
215
|
}) });
|
|
215
216
|
}
|
|
216
|
-
function CornerButton({ corner, label, shortcut, onClick, disabled, children }) {
|
|
217
|
+
function CornerButton({ corner, label, shortcut, onClick, disabled, pressed, children }) {
|
|
217
218
|
return (
|
|
218
219
|
// ui-exception: the deck's four corner targets sit in its own frame geometry
|
|
219
220
|
/* @__PURE__ */ jsx(
|
|
@@ -226,6 +227,7 @@ function CornerButton({ corner, label, shortcut, onClick, disabled, children })
|
|
|
226
227
|
title: shortcut ? `${label} (${shortcut})` : label,
|
|
227
228
|
"aria-keyshortcuts": shortcut,
|
|
228
229
|
disabled,
|
|
230
|
+
"aria-pressed": pressed,
|
|
229
231
|
onClick,
|
|
230
232
|
children
|
|
231
233
|
}
|
|
@@ -742,17 +744,17 @@ function useDeckController({ items, binding, initialState, onChange }) {
|
|
|
742
744
|
const stateRef = React2.useRef(state);
|
|
743
745
|
stateRef.current = state;
|
|
744
746
|
const send = React2.useCallback(
|
|
745
|
-
(ops, onRefused) => {
|
|
747
|
+
(ops, onRefused, transient = false) => {
|
|
746
748
|
if (!binding) {
|
|
747
749
|
setLocal((s) => applyOps(s, ops));
|
|
748
750
|
return;
|
|
749
751
|
}
|
|
750
752
|
const id = ++seq.current;
|
|
751
|
-
setPending((list2) => [...list2, { id, ops, settledAt: null }]);
|
|
753
|
+
setPending((list2) => [...list2, { id, ops, settledAt: null, ...transient ? { transient } : {} }]);
|
|
752
754
|
binding.apply(ops).then(
|
|
753
755
|
() => {
|
|
754
756
|
setWriteError(null);
|
|
755
|
-
setPending((list2) => list2.map((p) => p.id === id ? { ...p, settledAt: Date.now() } : p));
|
|
757
|
+
setPending((list2) => transient ? list2.filter((p) => p.id !== id) : list2.map((p) => p.id === id ? { ...p, settledAt: Date.now() } : p));
|
|
756
758
|
},
|
|
757
759
|
(err) => {
|
|
758
760
|
setPending((list2) => list2.filter((p) => p.id !== id));
|
|
@@ -767,7 +769,7 @@ function useDeckController({ items, binding, initialState, onChange }) {
|
|
|
767
769
|
(change) => {
|
|
768
770
|
touched.current = true;
|
|
769
771
|
setHistory((h) => [...h, change]);
|
|
770
|
-
send(change.ops, () => setHistory((h) => h.filter((c) => c !== change)));
|
|
772
|
+
send(change.ops, () => setHistory((h) => h.filter((c) => c !== change)), change.transient);
|
|
771
773
|
onChangeRef.current?.(applyOps(stateRef.current, change.ops), change, false);
|
|
772
774
|
},
|
|
773
775
|
[send]
|
|
@@ -779,7 +781,7 @@ function useDeckController({ items, binding, initialState, onChange }) {
|
|
|
779
781
|
if (!last) return null;
|
|
780
782
|
touched.current = true;
|
|
781
783
|
setHistory((h) => h.slice(0, -1));
|
|
782
|
-
send(last.inverse, () => setHistory((h) => [...h, last]));
|
|
784
|
+
send(last.inverse, () => setHistory((h) => [...h, last]), last.transient);
|
|
783
785
|
onChangeRef.current?.(applyOps(stateRef.current, last.inverse), last, true);
|
|
784
786
|
return last;
|
|
785
787
|
}, [send]);
|
|
@@ -970,6 +972,8 @@ var DEFAULT_SWIPE_DECK_LABELS = {
|
|
|
970
972
|
allDone: "All done",
|
|
971
973
|
answeredOf: "{answered} of {total} answered",
|
|
972
974
|
yourAnswers: "Your answers",
|
|
975
|
+
answered: "Answered",
|
|
976
|
+
backToCards: "Back to cards",
|
|
973
977
|
change: "Change",
|
|
974
978
|
rightAnswer: "Right answer",
|
|
975
979
|
right: "Right",
|
|
@@ -1423,9 +1427,13 @@ function SwipeDeck(props) {
|
|
|
1423
1427
|
const [bubble, setBubble] = React4.useState(null);
|
|
1424
1428
|
const [toast, setToast] = React4.useState(null);
|
|
1425
1429
|
const [said, setSaid] = React4.useState("");
|
|
1426
|
-
const
|
|
1430
|
+
const [reviewing, setReviewing] = React4.useState(false);
|
|
1431
|
+
const reviewingRef = React4.useRef(false);
|
|
1432
|
+
reviewingRef.current = reviewing;
|
|
1433
|
+
const cardItem = step.kind === "card" && !reviewing ? step.item : null;
|
|
1427
1434
|
const cardKey = cardItem ? keyFor(rules, cardItem) : deckKey;
|
|
1428
1435
|
const cardMore = React4.useMemo(() => cardItem ? moreFor(rules, cardItem) : [], [cardItem, rules]);
|
|
1436
|
+
const cardMoreShown = React4.useMemo(() => cardMore.filter((a) => !a.hidden), [cardMore]);
|
|
1429
1437
|
const suggestedDir = cardItem ? directionOf(cardKey, cardItem.suggested) : null;
|
|
1430
1438
|
const [cardDetail, setCardDetail] = React4.useState(null);
|
|
1431
1439
|
const detailNow = cardItem ? cardDetail?.id === cardItem.id ? cardDetail.detail : state.details?.[cardItem.id] ?? null : null;
|
|
@@ -1468,7 +1476,8 @@ function SwipeDeck(props) {
|
|
|
1468
1476
|
await flyOut(layerRef.current, dir ?? "down", speed);
|
|
1469
1477
|
const now = stateRef.current;
|
|
1470
1478
|
const rides = answerDetail(cardItem, detail === void 0 ? detailRef.current : detail);
|
|
1471
|
-
const
|
|
1479
|
+
const made = answerChange(now, cardItem, answer.id, rules, items, dir, rides);
|
|
1480
|
+
const change = answer.requeue && props.binding ? { ...made, transient: true } : made;
|
|
1472
1481
|
enterFrom.current = null;
|
|
1473
1482
|
setCardDetail(null);
|
|
1474
1483
|
setLocked(null);
|
|
@@ -1613,6 +1622,13 @@ function SwipeDeck(props) {
|
|
|
1613
1622
|
const afterTour = React4.useRef(null);
|
|
1614
1623
|
const runKeyRef = React4.useRef(() => false);
|
|
1615
1624
|
runKeyRef.current = (key, target) => {
|
|
1625
|
+
if (reviewingRef.current) {
|
|
1626
|
+
if (key === "Escape") {
|
|
1627
|
+
setReviewing(false);
|
|
1628
|
+
return true;
|
|
1629
|
+
}
|
|
1630
|
+
if (key !== "z" && key !== "Z" && key !== "Backspace") return false;
|
|
1631
|
+
}
|
|
1616
1632
|
const dir = KEYS[key];
|
|
1617
1633
|
const shortcut = !dir && key.length === 1 ? shortcutRef.current(key) : null;
|
|
1618
1634
|
if ((dir || shortcut) && lockedRef.current) return false;
|
|
@@ -1654,7 +1670,7 @@ function SwipeDeck(props) {
|
|
|
1654
1670
|
const a2 = cardKey[d];
|
|
1655
1671
|
if (a2?.shortcut?.toLowerCase() === k) return { answer: a2, dir: d };
|
|
1656
1672
|
}
|
|
1657
|
-
const a =
|
|
1673
|
+
const a = cardMoreShown.find((x) => x.shortcut?.toLowerCase() === k);
|
|
1658
1674
|
return a ? { answer: a, dir: null } : null;
|
|
1659
1675
|
};
|
|
1660
1676
|
const exitRef = React4.useRef({ kind: props.exitKind, onExit: props.onExit });
|
|
@@ -1670,6 +1686,11 @@ function SwipeDeck(props) {
|
|
|
1670
1686
|
if (layout === "inline" && !(root && (root.contains(active ?? null) || root.matches(":hover")))) return;
|
|
1671
1687
|
const t = e.target instanceof Element ? e.target : null;
|
|
1672
1688
|
if (t?.closest("input, textarea, select, [contenteditable='true']")) return;
|
|
1689
|
+
if ((e.ctrlKey || e.metaKey) && !e.altKey && !e.shiftKey && (e.key === "z" || e.key === "Z") && !e.repeat) {
|
|
1690
|
+
e.preventDefault();
|
|
1691
|
+
undoRef.current();
|
|
1692
|
+
return;
|
|
1693
|
+
}
|
|
1673
1694
|
if (e.altKey || e.ctrlKey || e.metaKey) return;
|
|
1674
1695
|
if (e.repeat) {
|
|
1675
1696
|
if (KEYS[e.key] || e.key === "z" || e.key === "Z" || e.key === "Backspace") e.preventDefault();
|
|
@@ -1826,7 +1847,7 @@ function SwipeDeck(props) {
|
|
|
1826
1847
|
wasAtEnd.current = atEnd;
|
|
1827
1848
|
}, [atEnd, result, onComplete, labels]);
|
|
1828
1849
|
const copy = async () => {
|
|
1829
|
-
const text2 = props.copyText ? props.copyText({ item: cardItem, state, result }) : cardItem ? itemCopyText(cardItem, state, cardKey, labels, conflict,
|
|
1850
|
+
const text2 = props.copyText ? props.copyText({ item: cardItem, state, result }) : cardItem ? itemCopyText(cardItem, state, cardKey, labels, conflict, cardMoreShown) : deckCopyText(result, rules);
|
|
1830
1851
|
const ok = await copyToClipboard(text2);
|
|
1831
1852
|
flash(ok ? labels.copied : labels.copyFailed);
|
|
1832
1853
|
};
|
|
@@ -1880,11 +1901,41 @@ function SwipeDeck(props) {
|
|
|
1880
1901
|
},
|
|
1881
1902
|
children: [
|
|
1882
1903
|
props.onExpand ? /* @__PURE__ */ jsx3(CornerButton, { corner: "tl", label: labels.expand, onClick: props.onExpand, children: /* @__PURE__ */ jsx3(Maximize2Icon, {}) }) : props.onExit ? /* @__PURE__ */ jsx3(CornerButton, { corner: "tl", label: props.exitKind === "collapse" ? labels.collapse : labels.exit, ...props.exitKind === "collapse" ? { shortcut: "Escape" } : {}, onClick: props.onExit, children: props.exitKind === "collapse" ? /* @__PURE__ */ jsx3(Minimize2Icon, {}) : /* @__PURE__ */ jsx3(XIcon, {}) }) : null,
|
|
1883
|
-
/* @__PURE__ */
|
|
1904
|
+
/* @__PURE__ */ jsxs3(CornerButton, { corner: "tr", label: labels.answered, onClick: () => setReviewing((v) => !v), disabled: !ready || !items.length || step.kind === "end", pressed: reviewing, children: [
|
|
1905
|
+
/* @__PURE__ */ jsx3(ListChecksIcon, {}),
|
|
1906
|
+
result.answered ? /* @__PURE__ */ jsx3("span", { className: "matrx-sd-corner-count", children: result.answered }) : null
|
|
1907
|
+
] }),
|
|
1884
1908
|
/* @__PURE__ */ jsx3(CornerButton, { corner: "bl", label: labels.undo, shortcut: "Z", onClick: undo, disabled: !controller.canUndo, children: /* @__PURE__ */ jsx3(Undo2Icon, {}) }),
|
|
1885
1909
|
/* @__PURE__ */ jsx3(CornerButton, { corner: "br", label: labels.copy, onClick: () => void copy(), disabled: !ready || !items.length, children: /* @__PURE__ */ jsx3(CopyIcon, {}) }),
|
|
1886
1910
|
cardItem ? /* @__PURE__ */ jsx3(EdgeButtons, { keyMap: cardKey, suggested: suggestedDir, refs: edgeRefs, onAnswer: (d) => act(d), suggestionLabel: labels.suggestion }) : null,
|
|
1887
|
-
/* @__PURE__ */ jsx3("div", { className: "matrx-sd-stage", children: !ready ? /* @__PURE__ */ jsx3("div", { className: "matrx-sd-layer", "data-state": controller.status, children: controller.status === "error" ? /* @__PURE__ */ jsx3(ErrorBox, { className: "matrx-sd-message", message: controller.readError ?? "", operation: "Read the deck", origin: "design-system/SwipeDeck" }) : /* @__PURE__ */ jsx3(Loader2Icon, { className: "matrx-spin matrx-sd-spinner" }) }) : items.length === 0 ? /* @__PURE__ */ jsx3(EmptyView, { title: props.empty?.title ?? labels.emptyTitle, line: props.empty?.line, action: props.empty?.action, layerRef }, "empty") : step.kind
|
|
1911
|
+
/* @__PURE__ */ jsx3("div", { className: "matrx-sd-stage", children: !ready ? /* @__PURE__ */ jsx3("div", { className: "matrx-sd-layer", "data-state": controller.status, children: controller.status === "error" ? /* @__PURE__ */ jsx3(ErrorBox, { className: "matrx-sd-message", message: controller.readError ?? "", operation: "Read the deck", origin: "design-system/SwipeDeck" }) : /* @__PURE__ */ jsx3(Loader2Icon, { className: "matrx-spin matrx-sd-spinner" }) }) : items.length === 0 ? /* @__PURE__ */ jsx3(EmptyView, { title: props.empty?.title ?? labels.emptyTitle, line: props.empty?.line, action: props.empty?.action, layerRef }, "empty") : reviewing && step.kind !== "end" ? /* @__PURE__ */ jsx3(
|
|
1912
|
+
EndView,
|
|
1913
|
+
{
|
|
1914
|
+
result,
|
|
1915
|
+
rules,
|
|
1916
|
+
labels,
|
|
1917
|
+
groupLabels: props.groupLabels,
|
|
1918
|
+
layerRef,
|
|
1919
|
+
enterFrom,
|
|
1920
|
+
review: {
|
|
1921
|
+
onBack: () => setReviewing(false),
|
|
1922
|
+
onHelp: () => {
|
|
1923
|
+
setReviewing(false);
|
|
1924
|
+
void tour();
|
|
1925
|
+
}
|
|
1926
|
+
},
|
|
1927
|
+
onChange: (item) => {
|
|
1928
|
+
enterFrom.current = null;
|
|
1929
|
+
const now = stateRef.current;
|
|
1930
|
+
const ops = [{ kind: "answer", itemId: item.id, answer: null }];
|
|
1931
|
+
if (item.group && now.picks[item.group] === item.id) ops.push({ kind: "pick", group: item.group, itemId: null });
|
|
1932
|
+
controller.commit(makeChange(now, ops, items));
|
|
1933
|
+
setReviewing(false);
|
|
1934
|
+
setSaid(`${labels.change}: ${item.text}`);
|
|
1935
|
+
}
|
|
1936
|
+
},
|
|
1937
|
+
"review"
|
|
1938
|
+
) : step.kind === "card" ? /* @__PURE__ */ jsx3(
|
|
1888
1939
|
CardView,
|
|
1889
1940
|
{
|
|
1890
1941
|
item: step.item,
|
|
@@ -1893,7 +1944,7 @@ function SwipeDeck(props) {
|
|
|
1893
1944
|
conflict,
|
|
1894
1945
|
labels,
|
|
1895
1946
|
suggestedDir,
|
|
1896
|
-
more:
|
|
1947
|
+
more: cardMoreShown,
|
|
1897
1948
|
detail: detailNow,
|
|
1898
1949
|
onDetail: (d) => setCardDetail({ id: step.item.id, detail: d }),
|
|
1899
1950
|
body: cardContext && props.renderCardBody ? props.renderCardBody(cardContext) : null,
|
|
@@ -2237,7 +2288,7 @@ function groupOf(entry, graded) {
|
|
|
2237
2288
|
if (graded && entry.right !== null) return entry.right ? "right" : "wrong";
|
|
2238
2289
|
return entry.answer.label;
|
|
2239
2290
|
}
|
|
2240
|
-
function EndView({ result, rules, labels, groupLabels, layerRef, enterFrom, actions, onChange, children }) {
|
|
2291
|
+
function EndView({ result, rules, labels, groupLabels, layerRef, enterFrom, actions, onChange, children, review }) {
|
|
2241
2292
|
const layer = React4.useRef(null);
|
|
2242
2293
|
React4.useLayoutEffect(() => {
|
|
2243
2294
|
layerRef.current = layer.current;
|
|
@@ -2257,11 +2308,11 @@ function EndView({ result, rules, labels, groupLabels, layerRef, enterFrom, acti
|
|
|
2257
2308
|
const answered = result.entries.filter((e) => e.answer);
|
|
2258
2309
|
const shown = filter ? answered.filter((e) => groupOf(e, graded) === filter) : answered;
|
|
2259
2310
|
const pct = score && score.graded ? score.right / score.graded : 1;
|
|
2260
|
-
const kicker = first ? groupLabels?.[first[0]] ?? first[0] : score ? labels.score : null;
|
|
2261
|
-
const headline = first ? first[1].text : score ? `${score.right} / ${score.graded}` : labels.allDone;
|
|
2311
|
+
const kicker = review ? null : first ? groupLabels?.[first[0]] ?? first[0] : score ? labels.score : null;
|
|
2312
|
+
const headline = review ? labels.answered : first ? first[1].text : score ? `${score.right} / ${score.graded}` : labels.allDone;
|
|
2262
2313
|
const sub = labels.answeredOf.replace("{answered}", String(result.answered)).replace("{total}", String(result.total));
|
|
2263
|
-
return /* @__PURE__ */ jsx3("div", { ref: layer, className: "matrx-sd-layer matrx-sd-endlayer", children: /* @__PURE__ */ jsxs3("div", { className: "matrx-sd-end", "data-graded": graded ? "" : void 0, children: [
|
|
2264
|
-
/* @__PURE__ */ jsxs3("svg", { className: "matrx-sd-mark", viewBox: "0 0 72 72", "aria-hidden": "true", "data-tone": score ? pct >= 0.5 ? "success" : "warning" : "success", children: [
|
|
2314
|
+
return /* @__PURE__ */ jsx3("div", { ref: layer, className: "matrx-sd-layer matrx-sd-endlayer", children: /* @__PURE__ */ jsxs3("div", { className: "matrx-sd-end", "data-graded": graded ? "" : void 0, "data-review": review ? "" : void 0, children: [
|
|
2315
|
+
review ? null : /* @__PURE__ */ jsxs3("svg", { className: "matrx-sd-mark", viewBox: "0 0 72 72", "aria-hidden": "true", "data-tone": score ? pct >= 0.5 ? "success" : "warning" : "success", children: [
|
|
2265
2316
|
/* @__PURE__ */ jsx3("circle", { className: "matrx-sd-mark-track", cx: "36", cy: "36", r: "32" }),
|
|
2266
2317
|
/* @__PURE__ */ jsx3("circle", { className: "matrx-sd-mark-ring", cx: "36", cy: "36", r: "32", pathLength: 100, style: { strokeDasharray: `${Math.round(pct * 100)} 100` } }),
|
|
2267
2318
|
!score || pct === 1 ? /* @__PURE__ */ jsx3("path", { className: "matrx-sd-mark-check", d: "M23 37.5l9 9 17-19", pathLength: 100 }) : null
|
|
@@ -2269,11 +2320,11 @@ function EndView({ result, rules, labels, groupLabels, layerRef, enterFrom, acti
|
|
|
2269
2320
|
kicker ? /* @__PURE__ */ jsx3("div", { className: "matrx-sd-kicker", children: kicker }) : null,
|
|
2270
2321
|
/* @__PURE__ */ jsx3("h2", { className: "matrx-sd-end-hero", children: headline }),
|
|
2271
2322
|
/* @__PURE__ */ jsx3("div", { className: "matrx-sd-end-sub", children: sub }),
|
|
2272
|
-
score && first ? /* @__PURE__ */ jsxs3("div", { className: "matrx-sd-endline", children: [
|
|
2323
|
+
score && first && !review ? /* @__PURE__ */ jsxs3("div", { className: "matrx-sd-endline", children: [
|
|
2273
2324
|
/* @__PURE__ */ jsx3("div", { className: "matrx-sd-label", children: labels.score }),
|
|
2274
2325
|
/* @__PURE__ */ jsx3("div", { className: "matrx-sd-value", children: `${score.right} / ${score.graded}` })
|
|
2275
2326
|
] }) : null,
|
|
2276
|
-
rest.map(([group, item]) => /* @__PURE__ */ jsxs3("div", { className: "matrx-sd-endline", children: [
|
|
2327
|
+
(review ? [] : rest).map(([group, item]) => /* @__PURE__ */ jsxs3("div", { className: "matrx-sd-endline", children: [
|
|
2277
2328
|
/* @__PURE__ */ jsx3("div", { className: "matrx-sd-label", children: groupLabels?.[group] ?? group }),
|
|
2278
2329
|
/* @__PURE__ */ jsx3("div", { className: "matrx-sd-value", children: item.text })
|
|
2279
2330
|
] }, group)),
|
|
@@ -2310,6 +2361,8 @@ function EndView({ result, rules, labels, groupLabels, layerRef, enterFrom, acti
|
|
|
2310
2361
|
] }) : null,
|
|
2311
2362
|
shown.length ? /* @__PURE__ */ jsx3("ul", { className: "matrx-sd-review", "aria-label": labels.yourAnswers, children: shown.map((e) => {
|
|
2312
2363
|
const rightIds = e.item.correct === void 0 ? [] : typeof e.item.correct === "string" ? [e.item.correct] : e.item.correct;
|
|
2364
|
+
const said = typeof e.detail?.value === "string" && e.detail.value.trim() ? e.detail.value : e.item.text;
|
|
2365
|
+
const answerWords = typeof e.detail?.label === "string" && e.detail.label ? e.detail.label : e.answer?.label;
|
|
2313
2366
|
const rightWords = rightIds.map((id) => findAnswer(rules, e.item, id)?.label).filter(Boolean).join(", ");
|
|
2314
2367
|
return /* @__PURE__ */ jsx3("li", { children: /* @__PURE__ */ jsxs3(
|
|
2315
2368
|
"button",
|
|
@@ -2318,14 +2371,14 @@ function EndView({ result, rules, labels, groupLabels, layerRef, enterFrom, acti
|
|
|
2318
2371
|
className: "matrx-sd-review-row",
|
|
2319
2372
|
onClick: () => onChange(e.item),
|
|
2320
2373
|
"aria-label": [
|
|
2321
|
-
`${labels.change}: ${
|
|
2322
|
-
[
|
|
2374
|
+
`${labels.change}: ${said}`,
|
|
2375
|
+
[answerWords, e.right === true ? labels.right : e.right === false ? labels.wrong : null].filter(Boolean).join(", "),
|
|
2323
2376
|
e.right === false && rightWords ? `${labels.rightAnswer}: ${rightWords}` : null
|
|
2324
2377
|
].filter(Boolean).join(". "),
|
|
2325
2378
|
children: [
|
|
2326
2379
|
/* @__PURE__ */ jsxs3("span", { className: "matrx-sd-review-text", children: [
|
|
2327
2380
|
e.item.kicker ? /* @__PURE__ */ jsx3("span", { className: "matrx-sd-label", children: e.item.kicker }) : null,
|
|
2328
|
-
/* @__PURE__ */ jsx3("span", { className: "matrx-sd-review-item", children:
|
|
2381
|
+
/* @__PURE__ */ jsx3("span", { className: "matrx-sd-review-item", children: said }),
|
|
2329
2382
|
e.right === false && rightWords ? /* @__PURE__ */ jsxs3("span", { className: "matrx-sd-review-right", children: [
|
|
2330
2383
|
labels.rightAnswer,
|
|
2331
2384
|
": ",
|
|
@@ -2334,14 +2387,23 @@ function EndView({ result, rules, labels, groupLabels, layerRef, enterFrom, acti
|
|
|
2334
2387
|
] }),
|
|
2335
2388
|
/* @__PURE__ */ jsxs3("span", { className: "matrx-sd-review-answer", "data-tone": e.right === null ? e.answer?.tone : e.right ? "success" : "destructive", children: [
|
|
2336
2389
|
e.right === true ? /* @__PURE__ */ jsx3(CheckIcon, {}) : e.right === false ? /* @__PURE__ */ jsx3(XIcon, {}) : null,
|
|
2337
|
-
/* @__PURE__ */ jsx3("span", { children:
|
|
2390
|
+
/* @__PURE__ */ jsx3("span", { children: answerWords })
|
|
2338
2391
|
] }),
|
|
2339
2392
|
/* @__PURE__ */ jsx3(PencilIcon, { className: "matrx-sd-review-change", "aria-hidden": "true" })
|
|
2340
2393
|
]
|
|
2341
2394
|
}
|
|
2342
2395
|
) }, e.item.id);
|
|
2343
2396
|
}) }) : null,
|
|
2344
|
-
|
|
2397
|
+
review ? /* @__PURE__ */ jsxs3("div", { className: "matrx-sd-end-actions", children: [
|
|
2398
|
+
/* @__PURE__ */ jsx3("button", { type: "button", className: "matrx-sd-review-back", onClick: review.onBack, autoFocus: true, children: labels.backToCards }),
|
|
2399
|
+
review.onHelp ? (
|
|
2400
|
+
// ui-exception: the walkthrough, from the answered list (the corner it had now opens this list)
|
|
2401
|
+
/* @__PURE__ */ jsxs3("button", { type: "button", className: "matrx-sd-legend-chip", onClick: review.onHelp, children: [
|
|
2402
|
+
/* @__PURE__ */ jsx3(CircleHelpIcon, { "aria-hidden": "true" }),
|
|
2403
|
+
/* @__PURE__ */ jsx3("span", { children: labels.help })
|
|
2404
|
+
] })
|
|
2405
|
+
) : null
|
|
2406
|
+
] }) : actions ? /* @__PURE__ */ jsx3("div", { className: "matrx-sd-end-actions", children: actions }) : null
|
|
2345
2407
|
] }) });
|
|
2346
2408
|
}
|
|
2347
2409
|
function EmptyView({ title, line, action, layerRef }) {
|