@godxjp/ui 31.14.0 → 31.16.0

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
Files changed (36) hide show
  1. package/agent/START-HERE.md +5 -5
  2. package/agent/components/TextDiff.json +86 -0
  3. package/agent/components/Timeline.json +4 -3
  4. package/agent/components/Tree.json +22 -1
  5. package/agent/components-index.json +7 -2
  6. package/agent/components.json +112 -4
  7. package/agent/index.json +6 -6
  8. package/agent/llms.txt +6 -6
  9. package/agent/tokens.json +42 -0
  10. package/dist/components/data-display/index.d.ts +3 -1
  11. package/dist/components/data-display/index.js +4 -0
  12. package/dist/components/data-display/text-diff.d.ts +45 -0
  13. package/dist/components/data-display/text-diff.js +240 -0
  14. package/dist/components/data-display/timeline.d.ts +12 -2
  15. package/dist/components/data-display/timeline.js +6 -2
  16. package/dist/components/data-display/tree.d.ts +1 -1
  17. package/dist/components/data-display/tree.js +147 -0
  18. package/dist/contracts/measurement.json +1 -1
  19. package/dist/i18n/messages/en.json +18 -1
  20. package/dist/i18n/messages/ja.json +15 -1
  21. package/dist/i18n/messages/vi.json +15 -1
  22. package/dist/props/components/data-display.prop.d.ts +83 -1
  23. package/dist/props/registry.d.ts +88 -0
  24. package/dist/props/registry.js +109 -0
  25. package/dist/styles/data-display-layout.css +92 -1
  26. package/dist/styles/layers.json +6 -1
  27. package/dist/tokens/components/data-display.css +8 -0
  28. package/dist/tokens/components/tree.css +3 -0
  29. package/docs/FRAME-COVERAGE-REPORT.md +3 -2
  30. package/docs/data-display/text-diff.tsx +89 -0
  31. package/docs/data-display/timeline.tsx +28 -0
  32. package/docs/data-display/tree.tsx +82 -0
  33. package/docs/i18n/messages/en.json +41 -0
  34. package/docs/i18n/messages/ja.json +41 -0
  35. package/docs/i18n/messages/vi.json +41 -0
  36. package/package.json +2 -2
@@ -10,6 +10,7 @@ import {
10
10
  EmptyState,
11
11
  ScrollArea,
12
12
  Tree,
13
+ type TreeDropInfoProp,
13
14
  type TreeNodeProp,
14
15
  } from "@godxjp/ui/data-display";
15
16
  import { SearchInput } from "@godxjp/ui/data-entry";
@@ -246,6 +247,52 @@ function labelSuiteTree(
246
247
  });
247
248
  }
248
249
 
250
+ // ── card · draggable (gh#1093) ─────────────────────────────────────────────────────────────
251
+ const movablePagesSeed: TreeNodeProp[] = [
252
+ {
253
+ value: "guide",
254
+ label: "guide",
255
+ children: [
256
+ { value: "guide/start", label: "start" },
257
+ { value: "guide/setup", label: "setup" },
258
+ ],
259
+ },
260
+ { value: "faq", label: "faq" },
261
+ { value: "notes", label: "notes" },
262
+ ];
263
+
264
+ /** The seed's labels are catalogue keys (`treeDocs.drag.pages.*`), read in the reader's locale. */
265
+ function labelPages(
266
+ data: TreeNodeProp[],
267
+ t: (key: string) => string,
268
+ ): TreeNodeProp[] {
269
+ return data.map((node) => ({
270
+ ...node,
271
+ label: t(`treeDocs.drag.pages.${String(node.label)}`),
272
+ children: node.children ? labelPages(node.children, t) : undefined,
273
+ }));
274
+ }
275
+
276
+ /** What a consumer does in `onDrop`: take the node out, put it back where the drop says. */
277
+ function moveNode(data: TreeNodeProp[], info: TreeDropInfoProp): TreeNodeProp[] {
278
+ let moved: TreeNodeProp | undefined;
279
+ const without = (list: TreeNodeProp[]): TreeNodeProp[] =>
280
+ list
281
+ .filter((node) => (node.value === info.dragNode.value ? ((moved = node), false) : true))
282
+ .map((node) => (node.children ? { ...node, children: without(node.children) } : node));
283
+ const place = (list: TreeNodeProp[]): TreeNodeProp[] =>
284
+ list.flatMap((node) => {
285
+ if (node.value !== info.node.value) {
286
+ return node.children ? [{ ...node, children: place(node.children) }] : [node];
287
+ }
288
+ if (info.dropPosition === 0)
289
+ return [{ ...node, children: [...(node.children ?? []), moved!] }];
290
+ return info.dropPosition === -1 ? [moved!, node] : [node, moved!];
291
+ });
292
+ const rest = without(data);
293
+ return moved ? place(rest) : data;
294
+ }
295
+
249
296
  export default function Demo() {
250
297
  const { t } = useTranslation();
251
298
  // Card 1 — checks are controlled so the readout beside the tree can never disagree with it.
@@ -253,6 +300,8 @@ export default function Demo() {
253
300
  // Card 2 — selection is controlled and drives the detail pane.
254
301
  const [openFile, setOpenFile] = React.useState<string | undefined>("src/components/tree.tsx");
255
302
  // The page index — the tree IS the navigation, so selection is what the reading pane follows.
303
+ const [movablePages, setMovablePages] = React.useState(movablePagesSeed);
304
+ const [lastMove, setLastMove] = React.useState("");
256
305
  const [openPage, setOpenPage] = React.useState<string | undefined>("handbook/security/passwords");
257
306
  // Card 3 — async children land in state, exactly as a real fetch would.
258
307
  const [departments, setDepartments] = React.useState<Department[]>(initialDepartments);
@@ -452,6 +501,35 @@ export default function Demo() {
452
501
  </CardContent>
453
502
  </Card>
454
503
 
504
+ <Card>
505
+ <CardHeader>
506
+ <CardTitle level={2}>{t("treeDocs.drag.title")}</CardTitle>
507
+ <CardDescription>{t("treeDocs.drag.description")}</CardDescription>
508
+ </CardHeader>
509
+ <CardContent>
510
+ <Flex direction="col" gap="sm">
511
+ <Tree
512
+ aria-label={t("treeDocs.drag.treeLabel")}
513
+ treeData={labelPages(movablePages, t)}
514
+ defaultExpandAll
515
+ draggable
516
+ allowDrop={({ dropNode, dropPosition }) =>
517
+ !(dropNode.value === "notes" && dropPosition === 0)
518
+ }
519
+ onDrop={(info) => {
520
+ setMovablePages((current) => moveNode(current, info));
521
+ setLastMove(
522
+ `${String(info.dragNode.label)} → ${String(info.node.label)}(dropPosition ${info.dropPosition}, dropToGap ${info.dropToGap})`,
523
+ );
524
+ }}
525
+ />
526
+ <Text size="sm" tone="muted">
527
+ {t("treeDocs.drag.lastMove", { move: lastMove || t("treeDocs.drag.none") })}
528
+ </Text>
529
+ </Flex>
530
+ </CardContent>
531
+ </Card>
532
+
455
533
  <Card>
456
534
  <CardHeader>
457
535
  <CardTitle level={2}>組織ツリー(loadData · fieldNames · titleRender)</CardTitle>
@@ -632,6 +710,10 @@ export default function Demo() {
632
710
  },
633
711
  { label: "*", children: "同じ階層の兄弟をすべて展開" },
634
712
  { label: "文字キー", children: "先頭一致で次のノードへジャンプ(type-ahead)" },
713
+ {
714
+ label: "Alt + ↑ / ↓ / ← / →",
715
+ children: t("treeDocs.drag.keys"),
716
+ },
635
717
  ]}
636
718
  />
637
719
  </CardContent>
@@ -1507,6 +1507,21 @@
1507
1507
  "one": "Load {count} more",
1508
1508
  "other": "Load {count} more"
1509
1509
  }
1510
+ },
1511
+ "drag": {
1512
+ "title": "Drag to reorder or reparent (draggable · allowDrop · onDrop)",
1513
+ "description": "Drop on the upper quarter of a row to land before it, the lower quarter after it, the middle inside it. Tree never edits treeData; onDrop reports the move. From the keyboard: Alt+↑ / Alt+↓ move past a sibling, Alt+← outdents, Alt+→ indents into the previous sibling. Every move is announced in a live region. Here allowDrop refuses dropping inside “Release notes”.",
1514
+ "treeLabel": "Reorderable pages",
1515
+ "lastMove": "Last move: {move}",
1516
+ "none": "none",
1517
+ "keys": "When draggable: past a sibling / outdent / indent",
1518
+ "pages": {
1519
+ "guide": "User guide",
1520
+ "start": "Getting started",
1521
+ "setup": "Setup",
1522
+ "faq": "FAQ",
1523
+ "notes": "Release notes"
1524
+ }
1510
1525
  }
1511
1526
  },
1512
1527
  "progressDocs": {
@@ -1525,5 +1540,31 @@
1525
1540
  "home": "Home",
1526
1541
  "longSuite": "Q3 integration test · payment module · invoice re-issue scenarios",
1527
1542
  "longSection": "Acceptance criteria review for the release candidate of September 2026"
1543
+ },
1544
+ "timelineDocs": {
1545
+ "log": {
1546
+ "title": "status=\"log\" (activity log)",
1547
+ "description": "For a record of things that already happened, such as an issue history, use status=\"log\": a neutral dot and hairline rail, and no “Completed:” / “Upcoming:” prefix read out (antd's gray item).",
1548
+ "status": "Tanaka changed the status Open → In progress",
1549
+ "comment": "Nguyen commented",
1550
+ "assignee": "Tanaka changed the assignee"
1551
+ }
1552
+ },
1553
+ "textDiffDocs": {
1554
+ "subtitle": "Show what changed between two versions of a text, as removals and additions",
1555
+ "source": {
1556
+ "title": "See what changed in the original",
1557
+ "description": "The original a translation was written against, compared with the original now. Japanese is compared character by character, so changing one particle does not mark the whole sentence."
1558
+ },
1559
+ "policy": {
1560
+ "title": "Policy revision (side by side)",
1561
+ "description": "Unchanged lines fold away behind a button. Removals are struck through and additions underlined, so colour is never the only signal.",
1562
+ "before": "Before revision",
1563
+ "after": "After revision"
1564
+ },
1565
+ "words": {
1566
+ "title": "Alphabetic text, word by word",
1567
+ "description": "Languages that separate words with spaces are compared per word. Pass granularity=\"line\" to compare whole lines."
1568
+ }
1528
1569
  }
1529
1570
  }
@@ -1500,6 +1500,21 @@
1500
1500
  "loadMore": {
1501
1501
  "other": "さらに {count} 件を読み込む"
1502
1502
  }
1503
+ },
1504
+ "drag": {
1505
+ "title": "ドラッグで並べ替え・親を変更(draggable · allowDrop · onDrop)",
1506
+ "description": "行の上 1/4 に落とすと前へ、下 1/4 で後ろへ、中央でその中(子)へ移動します。Tree は treeData を書き換えず、onDrop で移動を知らせるだけです。キーボードでは Alt+↑ / Alt+↓ で兄弟の前後へ、Alt+← で階層を上げ、Alt+→ で直前の兄弟の中へ。移動は毎回ライブリージョンで読み上げられます。ここでは allowDrop で「リリースノート」の中へは落とせません。",
1507
+ "treeLabel": "並べ替えできるページ一覧",
1508
+ "lastMove": "最後の移動: {move}",
1509
+ "none": "なし",
1510
+ "keys": "draggable のとき:兄弟の前後へ/階層を上げる/階層を下げる",
1511
+ "pages": {
1512
+ "guide": "利用ガイド",
1513
+ "start": "はじめに",
1514
+ "setup": "初期設定",
1515
+ "faq": "よくある質問",
1516
+ "notes": "リリースノート"
1517
+ }
1503
1518
  }
1504
1519
  },
1505
1520
  "progressDocs": {
@@ -1518,5 +1533,31 @@
1518
1533
  "home": "ホーム",
1519
1534
  "longSuite": "第3四半期 結合テスト 決済モジュール 請求書再発行シナリオ",
1520
1535
  "longSection": "2026年9月 リリース候補の受入基準レビュー"
1536
+ },
1537
+ "timelineDocs": {
1538
+ "log": {
1539
+ "title": "status=\"log\"(アクティビティログ)",
1540
+ "description": "課題の履歴のように、すべて起きたことの記録には status=\"log\"。中立の点と細い線で描き、「完了:」「予定:」のような読み上げ接頭辞を付けません(antd の gray item と同じ)。",
1541
+ "status": "田中 がステータスを変更 未対応 → 処理中",
1542
+ "comment": "グエン がコメント",
1543
+ "assignee": "田中 が担当者を変更"
1544
+ }
1545
+ },
1546
+ "textDiffDocs": {
1547
+ "subtitle": "二つの版のテキストの差分を、削除と追加で示す",
1548
+ "source": {
1549
+ "title": "原文の変更を見る",
1550
+ "description": "翻訳を書いた時点の原文と、いまの原文の差分です。日本語は一文字ずつ比べるので、助詞ひとつの変更でも文全体が変わったようには見えません。"
1551
+ },
1552
+ "policy": {
1553
+ "title": "規程の改訂(左右に並べる)",
1554
+ "description": "変更のない行は折りたたまれ、ボタンで開けます。削除は取り消し線、追加は下線で示し、色だけに頼りません。",
1555
+ "before": "改訂前",
1556
+ "after": "改訂後"
1557
+ },
1558
+ "words": {
1559
+ "title": "英文は単語単位で",
1560
+ "description": "スペースで区切られる言語は単語ごとに比べます。行単位にしたい場合は granularity=\"line\" を指定します。"
1561
+ }
1521
1562
  }
1522
1563
  }
@@ -1500,6 +1500,21 @@
1500
1500
  "loadMore": {
1501
1501
  "other": "Tải thêm {count} ca"
1502
1502
  }
1503
+ },
1504
+ "drag": {
1505
+ "title": "Kéo để sắp xếp hoặc đổi cha (draggable · allowDrop · onDrop)",
1506
+ "description": "Thả vào 1/4 trên của dòng để đặt trước nó, 1/4 dưới để đặt sau, phần giữa để đặt vào trong. Tree không sửa treeData; onDrop báo nước đi. Bàn phím: Alt+↑ / Alt+↓ qua mục ngang hàng, Alt+← lùi cấp, Alt+→ thụt vào mục liền trước. Mỗi lần di chuyển được đọc qua live region. Ở đây allowDrop không cho thả vào trong “Ghi chú phát hành”.",
1507
+ "treeLabel": "Danh sách trang sắp xếp được",
1508
+ "lastMove": "Lần di chuyển cuối: {move}",
1509
+ "none": "chưa có",
1510
+ "keys": "Khi draggable: qua mục ngang hàng / lùi cấp / thụt cấp",
1511
+ "pages": {
1512
+ "guide": "Hướng dẫn sử dụng",
1513
+ "start": "Bắt đầu",
1514
+ "setup": "Cài đặt",
1515
+ "faq": "Câu hỏi thường gặp",
1516
+ "notes": "Ghi chú phát hành"
1517
+ }
1503
1518
  }
1504
1519
  },
1505
1520
  "progressDocs": {
@@ -1518,5 +1533,31 @@
1518
1533
  "home": "Trang chủ",
1519
1534
  "longSuite": "Kiểm thử tích hợp quý 3 · mô-đun thanh toán · kịch bản xuất lại hoá đơn",
1520
1535
  "longSection": "Rà soát tiêu chí nghiệm thu cho bản ứng viên tháng 9/2026"
1536
+ },
1537
+ "timelineDocs": {
1538
+ "log": {
1539
+ "title": "status=\"log\" (nhật ký hoạt động)",
1540
+ "description": "Với bản ghi những việc đã xảy ra như lịch sử issue, dùng status=\"log\": chấm trung tính, đường mảnh, không đọc tiền tố “Hoàn thành:” / “Sắp tới:” (giống item gray của antd).",
1541
+ "status": "Tanaka đổi trạng thái Mở → Đang xử lý",
1542
+ "comment": "Nguyễn đã bình luận",
1543
+ "assignee": "Tanaka đổi người phụ trách"
1544
+ }
1545
+ },
1546
+ "textDiffDocs": {
1547
+ "subtitle": "Cho thấy điều gì đã đổi giữa hai phiên bản của một văn bản, dưới dạng phần xoá và phần thêm",
1548
+ "source": {
1549
+ "title": "Xem thay đổi của bản gốc",
1550
+ "description": "Bản gốc lúc viết bản dịch so với bản gốc hiện tại. Tiếng Nhật được so từng ký tự, nên đổi một trợ từ không làm cả câu bị đánh dấu."
1551
+ },
1552
+ "policy": {
1553
+ "title": "Sửa đổi quy định (đặt cạnh nhau)",
1554
+ "description": "Các dòng không đổi được thu gọn sau một nút. Phần xoá bị gạch ngang, phần thêm được gạch chân, không chỉ dựa vào màu.",
1555
+ "before": "Trước sửa đổi",
1556
+ "after": "Sau sửa đổi"
1557
+ },
1558
+ "words": {
1559
+ "title": "Văn bản chữ Latinh, theo từng từ",
1560
+ "description": "Ngôn ngữ tách từ bằng dấu cách được so theo từng từ. Truyền granularity=\"line\" để so cả dòng."
1561
+ }
1521
1562
  }
1522
1563
  }
package/package.json CHANGED
@@ -1,7 +1,7 @@
1
1
  {
2
2
  "name": "@godxjp/ui",
3
- "version": "31.14.0",
4
- "godxUiMcp": "31.14.0",
3
+ "version": "31.16.0",
4
+ "godxUiMcp": "31.16.0",
5
5
  "license": "Apache-2.0",
6
6
  "repository": {
7
7
  "type": "git",