@godxjp/ui 22.0.0 → 23.1.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 (115) hide show
  1. package/README.md +4 -4
  2. package/dist/app/date-format-labels.d.ts +14 -2
  3. package/dist/app/date-format-labels.js +1 -1
  4. package/dist/app/date-formats.d.ts +14 -2
  5. package/dist/app/date-formats.js +9 -2
  6. package/dist/components/data-display/data-table.d.ts +8 -1
  7. package/dist/components/data-display/data-table.js +9 -2
  8. package/dist/components/data-display/scroll-area.d.ts +24 -4
  9. package/dist/components/data-display/scroll-area.js +34 -72
  10. package/dist/components/data-entry/cascader.js +8 -6
  11. package/dist/components/data-entry/checkbox.js +3 -1
  12. package/dist/components/data-entry/choice-hit-target.d.ts +24 -0
  13. package/dist/components/data-entry/choice-hit-target.js +12 -0
  14. package/dist/components/data-entry/control-surface.d.ts +8 -0
  15. package/dist/components/data-entry/control-surface.js +10 -1
  16. package/dist/components/data-entry/form-field.js +5 -4
  17. package/dist/components/data-entry/input.js +1 -1
  18. package/dist/components/data-entry/number-input.js +27 -6
  19. package/dist/components/data-entry/radio.js +4 -3
  20. package/dist/components/data-entry/search-select.js +225 -95
  21. package/dist/components/data-entry/select.d.ts +76 -14
  22. package/dist/components/data-entry/select.js +495 -163
  23. package/dist/components/data-entry/slider.d.ts +3 -11
  24. package/dist/components/data-entry/slider.js +582 -93
  25. package/dist/components/data-entry/switch.js +3 -1
  26. package/dist/components/feedback/dialog.js +2 -2
  27. package/dist/components/feedback/sheet.js +2 -22
  28. package/dist/components/navigation/dropdown-menu.d.ts +11 -3
  29. package/dist/components/navigation/dropdown-menu.js +190 -15
  30. package/dist/components/navigation/filter-bar.js +2 -1
  31. package/dist/components/navigation/index.d.ts +0 -3
  32. package/dist/components/navigation/index.js +0 -78
  33. package/dist/components/navigation/tabs.js +16 -4
  34. package/dist/components/ui/index.d.ts +0 -3
  35. package/dist/components/ui/index.js +0 -3
  36. package/dist/components/ui/input-otp.d.ts +1 -1
  37. package/dist/components/ui/segmented.js +3 -1
  38. package/dist/components/ui/tag-input.js +3 -5
  39. package/dist/i18n/messages/en.json +5 -1
  40. package/dist/i18n/messages/ja.json +5 -1
  41. package/dist/i18n/messages/vi.json +5 -1
  42. package/dist/lib/breakpoint-token.d.ts +8 -0
  43. package/dist/lib/breakpoint-token.js +29 -0
  44. package/dist/lib/select-options.d.ts +21 -0
  45. package/dist/lib/select-options.js +46 -0
  46. package/dist/props/components/data-display.prop.d.ts +17 -7
  47. package/dist/props/components/data-entry.prop.d.ts +323 -30
  48. package/dist/props/components/index.d.ts +1 -1
  49. package/dist/props/components/navigation.prop.d.ts +25 -1
  50. package/dist/props/registry.d.ts +69 -1
  51. package/dist/props/registry.js +75 -0
  52. package/dist/props/vocabulary/data.prop.d.ts +5 -0
  53. package/dist/props/vocabulary/index.d.ts +1 -1
  54. package/dist/styles/control.css +246 -28
  55. package/dist/styles/data-display-layout.css +18 -10
  56. package/dist/styles/focus-ring.css +28 -0
  57. package/dist/styles/fonts.css +88 -4
  58. package/dist/styles/form-layout.css +4 -0
  59. package/dist/styles/layout.css +2 -1
  60. package/dist/styles/navigation-layout.css +24 -238
  61. package/dist/styles/shell-layout.css +148 -139
  62. package/dist/styles/table-layout.css +12 -5
  63. package/dist/tokens/components/control.css +12 -3
  64. package/dist/tokens/components/data-display.css +0 -5
  65. package/dist/tokens/components/navigation.css +5 -5
  66. package/dist/tokens/components/scroll-area.css +7 -0
  67. package/docs/CONSUMER-RULES.md +7 -2
  68. package/docs/CUSTOMER-THEMING.md +25 -9
  69. package/docs/DATETIME.md +11 -2
  70. package/docs/FRAME-COVERAGE-REPORT.md +4 -7
  71. package/docs/SPACING.md +35 -5
  72. package/docs/TOKENS.md +1 -1
  73. package/docs/data-display/data-table/index.tsx +44 -3
  74. package/docs/data-display/popover.tsx +4 -6
  75. package/docs/data-display/scroll-area.tsx +51 -45
  76. package/docs/data-display/table.tsx +1 -1
  77. package/docs/data-entry/date-picker.tsx +2 -3
  78. package/docs/data-entry/input-otp.tsx +5 -2
  79. package/docs/data-entry/segmented-in-filter-row.tsx +77 -0
  80. package/docs/data-entry/segmented.tsx +40 -1
  81. package/docs/data-entry/select-matrix.tsx +1 -2
  82. package/docs/data-entry/select.tsx +108 -3
  83. package/docs/data-entry/slider.tsx +125 -47
  84. package/docs/feedback/dialog.tsx +1 -2
  85. package/docs/feedback/sheet.tsx +1 -2
  86. package/docs/layout/app-shell-states.tsx +143 -0
  87. package/docs/navigation/dropdown-menu.tsx +77 -6
  88. package/docs/navigation/tabs.tsx +72 -0
  89. package/docs/roadmap/ai-chat-components.md +1 -2
  90. package/docs/roadmap/parity-audit-data-entry.md +44 -33
  91. package/docs/roadmap/parity-audit-layout-navigation-general.md +304 -310
  92. package/docs/roadmap/parity-backlog.md +2 -3
  93. package/docs/roadmap/tree-components.md +0 -1
  94. package/package.json +25 -55
  95. package/scripts/_agent-setup.mjs +18 -0
  96. package/scripts/guinea-pig-skill.md +12 -6
  97. package/scripts/ui-audit.mjs +185 -7
  98. package/scripts/visual-audit-rules.mjs +0 -7
  99. package/scripts/visual-audit.mjs +6 -27
  100. package/dist/components/navigation/context-menu.d.ts +0 -21
  101. package/dist/components/navigation/context-menu.js +0 -149
  102. package/dist/components/navigation/menubar.d.ts +0 -28
  103. package/dist/components/navigation/menubar.js +0 -136
  104. package/dist/components/navigation/navigation-menu.d.ts +0 -10
  105. package/dist/components/navigation/navigation-menu.js +0 -91
  106. package/dist/components/ui/context-menu.d.ts +0 -1
  107. package/dist/components/ui/context-menu.js +0 -2
  108. package/dist/components/ui/menubar.d.ts +0 -1
  109. package/dist/components/ui/menubar.js +0 -2
  110. package/dist/components/ui/navigation-menu.d.ts +0 -1
  111. package/dist/components/ui/navigation-menu.js +0 -2
  112. package/docs/FRAME-A11Y-CI.md +0 -349
  113. package/docs/navigation/context-menu.tsx +0 -128
  114. package/docs/navigation/menubar.tsx +0 -141
  115. package/docs/navigation/navigation-menu.tsx +0 -158
@@ -341,7 +341,9 @@
341
341
  },
342
342
  "numberInput": {
343
343
  "increment": "Increase",
344
- "decrement": "Decrease"
344
+ "decrement": "Decrease",
345
+ "incrementField": "Increase {label}",
346
+ "decrementField": "Decrease {label}"
345
347
  }
346
348
  },
347
349
  "navigation": {
@@ -368,6 +370,7 @@
368
370
  },
369
371
  "filterBar": {
370
372
  "appliedFilters": "Applied filters",
373
+ "clearFilter": "Clear {label} selection",
371
374
  "removeFilter": "Remove filter: {label}",
372
375
  "resultCount": {
373
376
  "one": "{count} result",
@@ -442,6 +445,7 @@
442
445
  },
443
446
  "dateFormat": {
444
447
  "iso": "ISO (yyyy-MM-dd)",
448
+ "ymd": "Year / Month / Day (yyyy/MM/dd)",
445
449
  "dmy": "Day / Month / Year",
446
450
  "mdy": "Month / Day / Year"
447
451
  },
@@ -334,7 +334,9 @@
334
334
  },
335
335
  "numberInput": {
336
336
  "increment": "増やす",
337
- "decrement": "減らす"
337
+ "decrement": "減らす",
338
+ "incrementField": "{label}を増やす",
339
+ "decrementField": "{label}を減らす"
338
340
  }
339
341
  },
340
342
  "navigation": {
@@ -361,6 +363,7 @@
361
363
  },
362
364
  "filterBar": {
363
365
  "appliedFilters": "適用中のフィルター",
366
+ "clearFilter": "{label}の選択をクリア",
364
367
  "removeFilter": "フィルターを解除: {label}",
365
368
  "resultCount": "{count} 件の結果"
366
369
  },
@@ -429,6 +432,7 @@
429
432
  },
430
433
  "dateFormat": {
431
434
  "iso": "YYYY-MM-DD(年-月-日)",
435
+ "ymd": "YYYY/MM/DD(年/月/日)",
432
436
  "dmy": "日/月/年",
433
437
  "mdy": "月/日/年"
434
438
  },
@@ -335,7 +335,9 @@
335
335
  },
336
336
  "numberInput": {
337
337
  "increment": "Tăng",
338
- "decrement": "Giảm"
338
+ "decrement": "Giảm",
339
+ "incrementField": "Tăng {label}",
340
+ "decrementField": "Giảm {label}"
339
341
  }
340
342
  },
341
343
  "navigation": {
@@ -362,6 +364,7 @@
362
364
  },
363
365
  "filterBar": {
364
366
  "appliedFilters": "Bộ lọc đang áp dụng",
367
+ "clearFilter": "Xóa lựa chọn {label}",
365
368
  "removeFilter": "Bỏ bộ lọc: {label}",
366
369
  "resultCount": "{count} kết quả"
367
370
  },
@@ -430,6 +433,7 @@
430
433
  },
431
434
  "dateFormat": {
432
435
  "iso": "ISO (yyyy-MM-dd)",
436
+ "ymd": "Năm / Tháng / Ngày (yyyy/MM/dd)",
433
437
  "dmy": "Ngày / Tháng / Năm",
434
438
  "mdy": "Tháng / Ngày / Năm"
435
439
  },
@@ -0,0 +1,8 @@
1
+ /**
2
+ * True while the viewport is at or below the width the theme token `token` names.
3
+ *
4
+ * The token is read once per mount rather than at module scope: the fallback is what SSR and the
5
+ * first client render agree on, and the themed value arrives in the effect. Same-value updates
6
+ * bail out inside React, so a theme that left the default alone re-renders nothing.
7
+ */
8
+ export declare function useMaxWidthBreakpoint(token: string, fallbackQuery: string): boolean;
@@ -0,0 +1,29 @@
1
+ "use client";
2
+ import * as React from "react";
3
+ import { useMediaQuery } from "./hooks.js";
4
+ function cssLengthToPx(value, rootFontSize) {
5
+ const match = /^(-?\d*\.?\d+)(px|rem|em)?$/.exec(value.trim());
6
+ if (match == null) return void 0;
7
+ const amount = Number(match[1]);
8
+ if (!Number.isFinite(amount)) return void 0;
9
+ return match[2] === "rem" || match[2] === "em" ? amount * rootFontSize : amount;
10
+ }
11
+ function readMaxWidthQuery(token, fallbackQuery) {
12
+ if (typeof document === "undefined" || typeof window.getComputedStyle !== "function") {
13
+ return fallbackQuery;
14
+ }
15
+ const rootStyle = window.getComputedStyle(document.documentElement);
16
+ const rootFontSize = cssLengthToPx(rootStyle.fontSize || "16px", 16) ?? 16;
17
+ const px = cssLengthToPx(rootStyle.getPropertyValue(token), rootFontSize);
18
+ return px == null ? fallbackQuery : `(max-width: ${String(px)}px)`;
19
+ }
20
+ function useMaxWidthBreakpoint(token, fallbackQuery) {
21
+ const [query, setQuery] = React.useState(fallbackQuery);
22
+ React.useEffect(() => {
23
+ setQuery(readMaxWidthQuery(token, fallbackQuery));
24
+ }, [token, fallbackQuery]);
25
+ return useMediaQuery(query);
26
+ }
27
+ export {
28
+ useMaxWidthBreakpoint
29
+ };
@@ -0,0 +1,21 @@
1
+ import type { SearchSelectOptionProp, SelectFieldNamesProp, SelectOptionGroupProp } from "../props/components/data-entry.prop.js";
2
+ /**
3
+ * One list of rows, whatever shape the call site had.
4
+ *
5
+ * `Select` accepts three spellings of the same thing and they all have to arrive at the engine as
6
+ * ONE flat array, or every feature downstream (filtering, `maxCount`, the hidden `<option>` list)
7
+ * would need to know about all three:
8
+ *
9
+ * • this library's flat rows, `{ value, label, group? }`
10
+ * • antd's nested groups, `{ label, options: [...] }`
11
+ * • a foreign row read through `fieldNames`, `{ id, name, children }`
12
+ *
13
+ * Written once, here, rather than in both `select.tsx` and `search-select.tsx` — the two branches
14
+ * of one component must not disagree about what an option is. Group headings survive as the flat
15
+ * `group` string the rows already carried, so a grouped list renders identically whichever
16
+ * spelling produced it.
17
+ */
18
+ /** A row whose keys are not known ahead of time — what `fieldNames` exists to read. */
19
+ type RawOption = Record<string, unknown>;
20
+ export declare function normalizeSelectOptions(options: readonly (SearchSelectOptionProp | SelectOptionGroupProp | RawOption)[] | undefined, fieldNames?: SelectFieldNamesProp): SearchSelectOptionProp[];
21
+ export {};
@@ -0,0 +1,46 @@
1
+ function text(value) {
2
+ if (typeof value === "string" || typeof value === "number" || typeof value === "bigint") {
3
+ return String(value);
4
+ }
5
+ return "";
6
+ }
7
+ function groupChildren(option, optionsKey) {
8
+ const children = option[optionsKey];
9
+ return Array.isArray(children) ? children : void 0;
10
+ }
11
+ function normalizeSelectOptions(options, fieldNames) {
12
+ if (!options?.length) return [];
13
+ const labelKey = fieldNames?.label ?? "label";
14
+ const valueKey = fieldNames?.value ?? "value";
15
+ const optionsKey = fieldNames?.options ?? "options";
16
+ const groupLabelKey = fieldNames?.groupLabel ?? labelKey;
17
+ const disabledKey = fieldNames?.disabled ?? "disabled";
18
+ const flat = [];
19
+ const push = (raw, group) => {
20
+ const value = text(raw[valueKey]);
21
+ const label = text(raw[labelKey]);
22
+ flat.push({
23
+ ...raw,
24
+ value,
25
+ // A row with no label reads as its own value — the id is at least identifiable, where an
26
+ // empty row is not selectable by sight or by type-to-select.
27
+ label: label || value,
28
+ disabled: raw[disabledKey] === true || void 0,
29
+ // A row inside a group takes the group's heading; a flat row keeps the `group` it declared.
30
+ group: group ?? (typeof raw.group === "string" ? raw.group : void 0)
31
+ });
32
+ };
33
+ for (const entry of options) {
34
+ const children = groupChildren(entry, optionsKey);
35
+ if (children) {
36
+ const heading = text(entry[groupLabelKey]) || void 0;
37
+ for (const child of children) push(child, heading);
38
+ continue;
39
+ }
40
+ push(entry, void 0);
41
+ }
42
+ return flat;
43
+ }
44
+ export {
45
+ normalizeSelectOptions
46
+ };
@@ -28,7 +28,7 @@ export type ProseProp = {
28
28
  className?: ClassNameProp;
29
29
  children?: ChildrenProp;
30
30
  };
31
- import type { ActionProp, ClassNameProp, DescriptionProp, IconProp, TitleProp, ColumnDefProp, GetRowIdProp, OnRowClickProp, OnSelectChangeProp, OnSortChangeProp, OnTableDensityChangeProp, SelectedIdsProp, SortStateProp, TableDensityProp, TablePresetProp, BreakpointProp, DensityProp, ChildrenProp, PendingProp, ToneProp, AvatarShapeProp, HeadingLevelProp, HandlerProp, SizeProp, LabelProp, IdProp, DescriptionsLayoutProp, DescriptionsColumnProp, DescriptionsSpanProp, DescriptionsItemsProp, SortDirectionProp, OnColumnFilterChangeProp, OnRowProp, TableExpandableProp, TableRowSelectionProp, TableScrollProp, TableStickyProp, TableSummaryProp, DisabledProp, ValueProp, DefaultValueProp, OnValueChangeProp } from "../vocabulary/index.js";
31
+ import type { ActionProp, ClassNameProp, DescriptionProp, IconProp, TitleProp, ColumnDefProp, GetRowIdProp, GetRowLabelProp, OnRowClickProp, OnSelectChangeProp, OnSortChangeProp, OnTableDensityChangeProp, SelectedIdsProp, SortStateProp, TableDensityProp, TablePresetProp, BreakpointProp, DensityProp, ChildrenProp, PendingProp, ToneProp, AvatarShapeProp, HeadingLevelProp, HandlerProp, SizeProp, LabelProp, IdProp, DescriptionsLayoutProp, DescriptionsColumnProp, DescriptionsSpanProp, DescriptionsItemsProp, SortDirectionProp, OnColumnFilterChangeProp, OnRowProp, TableExpandableProp, TableRowSelectionProp, TableScrollProp, TableStickyProp, TableSummaryProp, DisabledProp, ValueProp, DefaultValueProp, OnValueChangeProp } from "../vocabulary/index.js";
32
32
  import type { TreeFieldNamesProp, TreeOptionProp } from "./data-entry.prop.js";
33
33
  /**
34
34
  * One key in a `Legend`: a tone, and the words that tone stands for.
@@ -255,6 +255,13 @@ export type DataTableProp<T> = {
255
255
  data: T[];
256
256
  columns: ColumnDefProp<T>[];
257
257
  getRowId?: GetRowIdProp<T>;
258
+ /**
259
+ * Human name of a row, announced by its selection checkbox or radio as "Select row {label}".
260
+ * Default: the text of the `priority: "primary"` column, else of the first column, when that
261
+ * value is a string or number; the row id only as a last resort. `rowSelection.getCheckboxProps`
262
+ * `aria-label` still overrides a single row.
263
+ */
264
+ getRowLabel?: GetRowLabelProp<T>;
258
265
  selectable?: boolean;
259
266
  selected?: SelectedIdsProp;
260
267
  onSelectChange?: OnSelectChangeProp;
@@ -403,9 +410,10 @@ export type PermissionMatrixProp = {
403
410
  export type ScrollAreaAnchorProp = "none" | "bottom";
404
411
  /** @see ScrollArea */
405
412
  /**
406
- * @see ScrollArea — which AXES scroll. This is not decoration: Radix sets the viewport's
407
- * `overflowX`/`overflowY` inline from which scrollbars are mounted, so an axis with no `ScrollBar`
408
- * is `overflow: hidden` and its content is CLIPPED, not merely un-barred.
413
+ * @see ScrollArea — which AXES scroll. This is not decoration: it IS the `overflow` the element
414
+ * carries, so an axis this does not name is `hidden` and its content is CLIPPED, not merely
415
+ * un-barred. It is also the whole replacement for mounting a `<ScrollBar>`, which was how the
416
+ * Radix-era component was told to open a second axis.
409
417
  *
410
418
  * `both` is a third value rather than an array or a pair of booleans because the axes are one
411
419
  * decision — a pane scrolls down, across, or freely — and a closed union is what `check:prop-vocabulary`
@@ -419,12 +427,14 @@ export type ScrollAreaProp = {
419
427
  *
420
428
  * Reach for `horizontal` for a strip of non-shrinking columns (a board, a lane of cards): the
421
429
  * viewport keeps its tab stop, so the strip is scrollable from the keyboard, and the consumer
422
- * writes no overflow styling of its own.
430
+ * writes no overflow styling of its own. `both` is what replaces a vertical area that also
431
+ * mounted `<ScrollBar orientation="horizontal" />`.
423
432
  */
424
433
  orientation?: ScrollAreaOrientationProp;
425
434
  /**
426
- * Ref to the element that actually SCROLLS the Radix viewport — not the root. The root is
427
- * `overflow: hidden` and never scrolls, so the component's own `ref` cannot serve.
435
+ * Ref to the element that actually SCROLLS. Since v23 that is the component's own element, so
436
+ * this and `ref` hand back the SAME node it is kept because it names the thing precisely, and
437
+ * because the Radix-era shape (a root wrapping a separate viewport) made `ref` the wrong handle.
428
438
  */
429
439
  viewportRef?: React.Ref<HTMLDivElement>;
430
440
  /** Edge the viewport sticks to as content grows. Default `none` (inert). */