@godxjp/ui 18.15.4 → 19.0.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.
- package/dist/app/date-format-labels.d.ts +1 -1
- package/dist/app/time-format-labels.d.ts +1 -1
- package/dist/components/data-display/badge.d.ts +1 -1
- package/dist/components/data-display/card.d.ts +4 -13
- package/dist/components/data-display/card.js +2 -15
- package/dist/components/data-display/data-table.d.ts +3 -8
- package/dist/components/data-display/data-table.js +106 -68
- package/dist/components/data-display/descriptions.js +34 -5
- package/dist/components/data-display/empty-state.js +1 -1
- package/dist/components/data-display/permission-matrix.js +7 -7
- package/dist/components/data-display/popover.js +2 -9
- package/dist/components/data-display/qr-code.d.ts +1 -1
- package/dist/components/data-display/scroll-area.d.ts +3 -1
- package/dist/components/data-display/scroll-area.js +150 -16
- package/dist/components/data-display/table.js +12 -3
- package/dist/components/data-entry/branch-scope-picker.js +4 -4
- package/dist/components/data-entry/calendar.js +15 -24
- package/dist/components/data-entry/cascader.js +67 -71
- package/dist/components/data-entry/checkbox.js +9 -1
- package/dist/components/data-entry/command.d.ts +6 -6
- package/dist/components/data-entry/date-picker.js +28 -15
- package/dist/components/data-entry/date-range-picker.js +10 -10
- package/dist/components/data-entry/form-field.js +7 -3
- package/dist/components/data-entry/index.d.ts +2 -1
- package/dist/components/data-entry/input.js +8 -19
- package/dist/components/data-entry/label.js +4 -2
- package/dist/components/data-entry/month-picker.js +16 -15
- package/dist/components/data-entry/month-range-picker.js +17 -16
- package/dist/components/data-entry/radio.js +6 -1
- package/dist/components/data-entry/search-select.js +29 -29
- package/dist/components/data-entry/select.js +15 -18
- package/dist/components/data-entry/switch.js +7 -1
- package/dist/components/data-entry/textarea.d.ts +56 -0
- package/dist/components/data-entry/textarea.js +103 -40
- package/dist/components/data-entry/time-picker.js +52 -52
- package/dist/components/data-entry/toggle-group.d.ts +1 -0
- package/dist/components/data-entry/toggle.d.ts +1 -1
- package/dist/components/data-entry/transfer.js +14 -15
- package/dist/components/data-entry/tree-select.js +16 -22
- package/dist/components/data-entry/upload-crop-dialog.js +4 -4
- package/dist/components/data-entry/upload.d.ts +1 -1
- package/dist/components/data-entry/upload.js +46 -46
- package/dist/components/feedback/alert.js +7 -14
- package/dist/components/feedback/dialog.d.ts +23 -32
- package/dist/components/feedback/dialog.js +16 -13
- package/dist/components/feedback/sheet.d.ts +1 -1
- package/dist/components/feedback/sheet.js +14 -14
- package/dist/components/feedback/skeleton.js +13 -10
- package/dist/components/feedback/sonner.d.ts +1 -1
- package/dist/components/feedback/sonner.js +17 -8
- package/dist/components/feedback/tooltip.js +1 -1
- package/dist/components/general/activity.d.ts +44 -0
- package/dist/components/general/activity.js +65 -0
- package/dist/components/general/button.d.ts +2 -2
- package/dist/components/general/button.js +11 -24
- package/dist/components/general/index.d.ts +2 -0
- package/dist/components/general/index.js +2 -0
- package/dist/components/layout/app-shell.js +5 -3
- package/dist/components/layout/auth-divider.d.ts +9 -2
- package/dist/components/layout/auth-divider.js +7 -11
- package/dist/components/layout/index.d.ts +1 -0
- package/dist/components/layout/page-container.d.ts +1 -1
- package/dist/components/layout/page-container.js +32 -20
- package/dist/components/layout/resizable.d.ts +12 -12
- package/dist/components/layout/separator.d.ts +1 -0
- package/dist/components/layout/service-role-panel.js +47 -42
- package/dist/components/layout/sidebar.js +13 -1
- package/dist/components/layout/split-pane.d.ts +12 -1
- package/dist/components/layout/split-pane.js +13 -4
- package/dist/components/navigation/app-setting-picker.js +5 -14
- package/dist/components/navigation/dropdown-menu.js +10 -16
- package/dist/components/navigation/menubar.d.ts +3 -6
- package/dist/components/navigation/pagination-utils.d.ts +15 -2
- package/dist/components/navigation/pagination-utils.js +27 -21
- package/dist/components/navigation/pagination.d.ts +4 -4
- package/dist/components/navigation/pagination.js +2 -2
- package/dist/components/navigation/steps.js +31 -67
- package/dist/components/navigation/tabs.js +17 -5
- package/dist/components/query/infinite-query-state.js +2 -2
- package/dist/components/ui/accordion.d.ts +1 -1
- package/dist/components/ui/avatar.d.ts +1 -1
- package/dist/components/ui/avatar.js +29 -10
- package/dist/components/ui/input-otp.d.ts +8 -6
- package/dist/components/ui/rating.js +1 -1
- package/dist/components/ui/separator.d.ts +27 -2
- package/dist/components/ui/separator.js +42 -11
- package/dist/components/ui/toggle-group.d.ts +15 -5
- package/dist/components/ui/toggle-group.js +43 -18
- package/dist/components/ui/toggle.d.ts +66 -5
- package/dist/components/ui/toggle.js +64 -9
- package/dist/i18n/messages/en.json +8 -0
- package/dist/i18n/messages/ja.json +8 -0
- package/dist/i18n/messages/vi.json +8 -0
- package/dist/lib/control-styles.d.ts +14 -0
- package/dist/lib/control-styles.js +2 -0
- package/dist/props/components/data-display.prop.d.ts +85 -3
- package/dist/props/components/data-entry.prop.d.ts +17 -0
- package/dist/props/components/general.prop.d.ts +52 -1
- package/dist/props/components/layout.prop.d.ts +137 -2
- package/dist/props/registry.d.ts +116 -5
- package/dist/props/registry.js +165 -4
- package/dist/props/vocabulary/index.d.ts +2 -2
- package/dist/props/vocabulary/interaction.prop.d.ts +15 -0
- package/dist/props/vocabulary/layout.prop.d.ts +8 -0
- package/dist/styles/alert-layout.css +69 -3
- package/dist/styles/badge-layout.css +2 -2
- package/dist/styles/base.css +6 -0
- package/dist/styles/card-layout.css +25 -8
- package/dist/styles/control.css +1150 -29
- package/dist/styles/data-display-layout.css +185 -11
- package/dist/styles/data-entry-layout.css +352 -1
- package/dist/styles/density.css +2 -2
- package/dist/styles/dialog-layout.css +203 -4
- package/dist/styles/focus-ring.css +155 -0
- package/dist/styles/form-layout.css +50 -5
- package/dist/styles/index.css +1 -0
- package/dist/styles/layout.css +412 -23
- package/dist/styles/motion.css +178 -0
- package/dist/styles/navigation-layout.css +398 -22
- package/dist/styles/shell-layout.css +137 -39
- package/dist/styles/table-layout.css +153 -22
- package/dist/styles/toggle.css +59 -0
- package/dist/tokens/base.css +5 -0
- package/dist/tokens/components/activity.css +64 -0
- package/dist/tokens/components/badge.css +7 -0
- package/dist/tokens/components/card.css +14 -10
- package/dist/tokens/components/chart.css +1 -1
- package/dist/tokens/components/control.css +358 -8
- package/dist/tokens/components/data-display.css +75 -0
- package/dist/tokens/components/data-entry.css +25 -0
- package/dist/tokens/components/descriptions.css +22 -0
- package/dist/tokens/components/feedback.css +143 -4
- package/dist/tokens/components/form.css +16 -0
- package/dist/tokens/components/legal-document.css +5 -1
- package/dist/tokens/components/navigation.css +109 -0
- package/dist/tokens/components/scroll-area.css +21 -0
- package/dist/tokens/components/separator.css +52 -0
- package/dist/tokens/components/shell.css +132 -20
- package/dist/tokens/components/table.css +52 -3
- package/dist/tokens/components/toggle.css +82 -0
- package/dist/tokens/components/upload.css +107 -0
- package/dist/tokens/foundation.css +171 -10
- package/dist/tokens/semantic/layout.css +120 -1
- package/package.json +84 -68
- package/scripts/ui-audit.mjs +51 -2
|
@@ -1,14 +1,14 @@
|
|
|
1
1
|
import * as React from "react";
|
|
2
2
|
import * as ResizablePrimitive from "react-resizable-panels";
|
|
3
|
-
export declare
|
|
4
|
-
|
|
5
|
-
displayName: string;
|
|
6
|
-
}
|
|
7
|
-
export declare
|
|
8
|
-
|
|
9
|
-
displayName: string;
|
|
10
|
-
}
|
|
11
|
-
export declare
|
|
12
|
-
|
|
13
|
-
displayName: string;
|
|
14
|
-
}
|
|
3
|
+
export declare function ResizablePanelGroup({ className, ...props }: React.ComponentPropsWithoutRef<typeof ResizablePrimitive.Group>): React.JSX.Element;
|
|
4
|
+
export declare namespace ResizablePanelGroup {
|
|
5
|
+
var displayName: string;
|
|
6
|
+
}
|
|
7
|
+
export declare function ResizablePanel({ className, elementRef, ...props }: React.ComponentPropsWithoutRef<typeof ResizablePrimitive.Panel>): React.JSX.Element;
|
|
8
|
+
export declare namespace ResizablePanel {
|
|
9
|
+
var displayName: string;
|
|
10
|
+
}
|
|
11
|
+
export declare function ResizableHandle({ className, ...props }: React.ComponentPropsWithoutRef<typeof ResizablePrimitive.Separator>): React.JSX.Element;
|
|
12
|
+
export declare namespace ResizableHandle {
|
|
13
|
+
var displayName: string;
|
|
14
|
+
}
|
|
@@ -132,49 +132,54 @@ const ServiceRolePanel = React.forwardRef(
|
|
|
132
132
|
masterLabel: masterLabel ?? t("layout.serviceRolePanel.rolesLabel"),
|
|
133
133
|
detailLabel: detailLabel ?? t("layout.serviceRolePanel.detailLabel"),
|
|
134
134
|
detailId,
|
|
135
|
-
master: /* @__PURE__ */ jsx("ul", { className: "
|
|
135
|
+
master: /* @__PURE__ */ jsx("ul", { className: "ui-service-role-panel-list", "data-slot": "service-role-panel-list", children: roles.map((role) => {
|
|
136
136
|
const selected = role.id === value;
|
|
137
|
-
return
|
|
138
|
-
|
|
139
|
-
|
|
140
|
-
|
|
141
|
-
|
|
142
|
-
|
|
143
|
-
|
|
144
|
-
|
|
145
|
-
|
|
146
|
-
|
|
147
|
-
|
|
148
|
-
|
|
149
|
-
|
|
150
|
-
|
|
151
|
-
|
|
152
|
-
|
|
153
|
-
|
|
154
|
-
|
|
155
|
-
|
|
156
|
-
|
|
157
|
-
|
|
158
|
-
|
|
159
|
-
|
|
160
|
-
|
|
161
|
-
|
|
162
|
-
|
|
163
|
-
|
|
164
|
-
|
|
165
|
-
|
|
166
|
-
|
|
167
|
-
|
|
168
|
-
|
|
169
|
-
|
|
170
|
-
|
|
171
|
-
|
|
172
|
-
|
|
173
|
-
|
|
174
|
-
|
|
175
|
-
|
|
176
|
-
|
|
177
|
-
|
|
137
|
+
return (
|
|
138
|
+
// NOT `.ui-inline-xs`: that helper adds `flex-wrap: wrap`, and this row holds a
|
|
139
|
+
// flex-1 select button next to an icon-only delete button that must never wrap
|
|
140
|
+
// onto its own line.
|
|
141
|
+
/* @__PURE__ */ jsxs("li", { className: "ui-service-role-panel-row", children: [
|
|
142
|
+
/* @__PURE__ */ jsx(
|
|
143
|
+
Button,
|
|
144
|
+
{
|
|
145
|
+
variant: selected ? "secondary" : "ghost",
|
|
146
|
+
className: "ui-service-role-panel-item h-auto flex-1 justify-start text-start",
|
|
147
|
+
"aria-current": selected ? "true" : void 0,
|
|
148
|
+
"aria-controls": detailId,
|
|
149
|
+
onClick: () => select(role.id),
|
|
150
|
+
children: /* @__PURE__ */ jsxs("span", { className: "ui-service-role-panel-item-body", children: [
|
|
151
|
+
/* @__PURE__ */ jsxs("span", { className: "ui-service-role-panel-item-title", children: [
|
|
152
|
+
/* @__PURE__ */ jsx(Text, { weight: "medium", className: "truncate", children: role.name }),
|
|
153
|
+
role.locked && /* @__PURE__ */ jsxs(Badge, { tone: "default", variant: "outline", children: [
|
|
154
|
+
/* @__PURE__ */ jsx(Lock, { "aria-hidden": "true" }),
|
|
155
|
+
t("layout.serviceRolePanel.locked")
|
|
156
|
+
] })
|
|
157
|
+
] }),
|
|
158
|
+
(role.description !== void 0 || role.memberCount !== void 0) && /* @__PURE__ */ jsx(Text, { size: "2xs", tone: "muted", className: "max-w-full truncate", children: [
|
|
159
|
+
role.description,
|
|
160
|
+
role.memberCount !== void 0 ? (
|
|
161
|
+
// `{count}` is Intl.NumberFormat-grouped by `interpolate`,
|
|
162
|
+
// pluralized by CLDR category — no hand-built formatting.
|
|
163
|
+
t("layout.serviceRolePanel.memberCount", {
|
|
164
|
+
count: role.memberCount
|
|
165
|
+
})
|
|
166
|
+
) : void 0
|
|
167
|
+
].filter((part) => part !== void 0).join(" \xB7 ") })
|
|
168
|
+
] })
|
|
169
|
+
}
|
|
170
|
+
),
|
|
171
|
+
deletable && !role.locked && /* @__PURE__ */ jsx(
|
|
172
|
+
Button,
|
|
173
|
+
{
|
|
174
|
+
variant: "ghost",
|
|
175
|
+
size: "icon-sm",
|
|
176
|
+
"aria-label": t("layout.serviceRolePanel.deleteRole", { role: role.name }),
|
|
177
|
+
onClick: () => setPendingDelete(role),
|
|
178
|
+
children: /* @__PURE__ */ jsx(Trash2, { "aria-hidden": "true" })
|
|
179
|
+
}
|
|
180
|
+
)
|
|
181
|
+
] }, role.id)
|
|
182
|
+
);
|
|
178
183
|
}) }),
|
|
179
184
|
children: detail
|
|
180
185
|
}
|
|
@@ -36,7 +36,19 @@ function SidebarRowContent({
|
|
|
36
36
|
return /* @__PURE__ */ jsxs(Fragment, { children: [
|
|
37
37
|
!sub ? /* @__PURE__ */ jsx(SidebarIcon, { icon: item.icon }) : null,
|
|
38
38
|
/* @__PURE__ */ jsx("span", { className: "sb-label", children: item.label }),
|
|
39
|
-
showBadge ?
|
|
39
|
+
showBadge ? (
|
|
40
|
+
// `data-tone` is emitted ONLY for the emphasis tone (rule #44: present-when-on,
|
|
41
|
+
// absent-when-off), so a rail that never sets `badgeTone` renders the exact same node it
|
|
42
|
+
// always did and no consumer selector has to out-specify a marker meaning "unchanged".
|
|
43
|
+
/* @__PURE__ */ jsx(
|
|
44
|
+
"span",
|
|
45
|
+
{
|
|
46
|
+
className: "sb-badge",
|
|
47
|
+
"data-tone": item.badgeTone === "destructive" ? "destructive" : void 0,
|
|
48
|
+
children: item.badge
|
|
49
|
+
}
|
|
50
|
+
)
|
|
51
|
+
) : null
|
|
40
52
|
] });
|
|
41
53
|
}
|
|
42
54
|
function SidebarItem({
|
|
@@ -1,7 +1,18 @@
|
|
|
1
1
|
import type { ReactNode } from "react";
|
|
2
2
|
export type SplitPaneProps = {
|
|
3
3
|
children: ReactNode;
|
|
4
|
-
|
|
4
|
+
/**
|
|
5
|
+
* Aside (trailing) panel content. Pass `null` to CLOSE the rail: no `<aside>` element is
|
|
6
|
+
* rendered, the grid drops to one full-width column and the gap goes with it.
|
|
7
|
+
*
|
|
8
|
+
* Closing this way — rather than dropping the whole `SplitPane` at the call site — is what
|
|
9
|
+
* keeps `children` MOUNTED. The three wrappers below are rendered unconditionally, so the
|
|
10
|
+
* main column sits at the same depth and the same slot in the React tree in both states and
|
|
11
|
+
* React reuses its DOM node instead of remounting it. A collapsible thread/detail panel that
|
|
12
|
+
* swapped `<SplitPane>{page}</SplitPane>` for a bare `{page}` changed the tree depth, which
|
|
13
|
+
* remounted the page and threw the reader to the bottom of a scrolled list.
|
|
14
|
+
*/
|
|
15
|
+
aside: ReactNode | null;
|
|
5
16
|
/**
|
|
6
17
|
* How wide the rail is once the pane is wide enough to split: `sm` 20rem,
|
|
7
18
|
* `md` 22rem, `lg` 30rem. `lg` is for rails that carry a panel rather than a
|
|
@@ -1,9 +1,18 @@
|
|
|
1
1
|
import { jsx, jsxs } from "react/jsx-runtime";
|
|
2
2
|
function SplitPane({ children, aside, asideWidth = "md", asideLabel }) {
|
|
3
|
-
|
|
4
|
-
|
|
5
|
-
|
|
6
|
-
|
|
3
|
+
const closed = aside === null || aside === void 0;
|
|
4
|
+
return /* @__PURE__ */ jsx("div", { className: "ui-split-pane-scope", children: /* @__PURE__ */ jsxs(
|
|
5
|
+
"div",
|
|
6
|
+
{
|
|
7
|
+
className: "ui-split-pane",
|
|
8
|
+
"data-aside-width": asideWidth,
|
|
9
|
+
"data-aside": closed ? "closed" : void 0,
|
|
10
|
+
children: [
|
|
11
|
+
/* @__PURE__ */ jsx("div", { className: "ui-split-pane-main", children }),
|
|
12
|
+
closed ? null : /* @__PURE__ */ jsx("aside", { className: "ui-split-pane-aside", "aria-label": asideLabel, children: aside })
|
|
13
|
+
]
|
|
14
|
+
}
|
|
15
|
+
) });
|
|
7
16
|
}
|
|
8
17
|
export {
|
|
9
18
|
SplitPane
|
|
@@ -41,16 +41,6 @@ const ICON = {
|
|
|
41
41
|
density: Rows3,
|
|
42
42
|
fontSize: Type
|
|
43
43
|
};
|
|
44
|
-
const TRIGGER_WIDTH = {
|
|
45
|
-
locale: "sm:w-40",
|
|
46
|
-
timezone: "sm:w-56",
|
|
47
|
-
dateFormat: "sm:w-44",
|
|
48
|
-
timeFormat: "sm:w-44",
|
|
49
|
-
theme: "sm:w-36",
|
|
50
|
-
brand: "sm:w-44",
|
|
51
|
-
density: "sm:w-40",
|
|
52
|
-
fontSize: "sm:w-36"
|
|
53
|
-
};
|
|
54
44
|
const ARIA_KEY = {
|
|
55
45
|
locale: "navigation.localePicker.ariaLabel",
|
|
56
46
|
timezone: "navigation.timezonePicker.ariaLabel",
|
|
@@ -139,7 +129,7 @@ const AppSettingPicker = React.forwardRef(
|
|
|
139
129
|
id,
|
|
140
130
|
showIndicator: !iconOnly && !inline,
|
|
141
131
|
className: cn(
|
|
142
|
-
inline ? "ui-app-setting-picker-inline
|
|
132
|
+
inline ? "ui-app-setting-picker-inline" : iconOnly ? (
|
|
143
133
|
// Structurally icon-only: drop the owned width + value spacing and square the box to
|
|
144
134
|
// the density-aware --control-height tap target, centring the icon. Visually it
|
|
145
135
|
// sits among ghost icon buttons (the topbar's sidebar-toggle/notifications/account
|
|
@@ -149,7 +139,7 @@ const AppSettingPicker = React.forwardRef(
|
|
|
149
139
|
// (`data-[state=open]:border-ring`, from controlTriggerClass) and the
|
|
150
140
|
// focus-visible ring are untouched, so keyboard and "is this open" affordance
|
|
151
141
|
// still hold.
|
|
152
|
-
"ui-app-setting-picker-icon hover:bg-accent hover:text-accent-foreground
|
|
142
|
+
"ui-app-setting-picker-icon hover:bg-accent hover:text-accent-foreground"
|
|
153
143
|
) : (
|
|
154
144
|
// Labeled: sized to a per-kind width from `sm` up; below `sm` it hugs its content and
|
|
155
145
|
// caps at the container (`w-auto max-w-full`) instead of the old UNCONDITIONAL
|
|
@@ -157,7 +147,7 @@ const AppSettingPicker = React.forwardRef(
|
|
|
157
147
|
// fill the bar (gh#165). A form field that wants a full-width control passes
|
|
158
148
|
// `className="w-full"`, which wins over `w-auto`.
|
|
159
149
|
// `compact` drops the per-kind width entirely so the trigger hugs its value.
|
|
160
|
-
cn("w-auto max-w-full", !isCompact &&
|
|
150
|
+
cn("w-auto max-w-full", !isCompact && "ui-app-setting-picker-trigger")
|
|
161
151
|
),
|
|
162
152
|
// Compact re-tiers the box through tokens (--app-setting-picker-compact-*); the height
|
|
163
153
|
// still comes from the official --control-height-sm tier, never a literal. The gap is a
|
|
@@ -165,13 +155,14 @@ const AppSettingPicker = React.forwardRef(
|
|
|
165
155
|
isCompact && "ui-app-setting-picker-compact gap-[length:var(--app-setting-picker-compact-gap)]",
|
|
166
156
|
className
|
|
167
157
|
),
|
|
158
|
+
"data-kind": kind,
|
|
168
159
|
"aria-label": t(ARIA_KEY[kind]),
|
|
169
160
|
children: [
|
|
170
161
|
inline ? null : /* @__PURE__ */ jsx(
|
|
171
162
|
Icon,
|
|
172
163
|
{
|
|
173
164
|
className: cn(
|
|
174
|
-
"
|
|
165
|
+
"ui-app-setting-picker-glyph",
|
|
175
166
|
// Compact relies on the trigger's tokenized flex gap instead of an icon margin.
|
|
176
167
|
!iconOnly && !isCompact && "me-2"
|
|
177
168
|
),
|
|
@@ -29,7 +29,7 @@ const DropdownMenuContent = React.forwardRef(({ className, sideOffset = 4, ...pr
|
|
|
29
29
|
"data-slot": "dropdown-menu-content",
|
|
30
30
|
sideOffset,
|
|
31
31
|
className: cn(
|
|
32
|
-
"
|
|
32
|
+
"ui-dropdown-menu-content data-[side=bottom]:slide-in-from-top-2 data-[side=left]:slide-in-from-right-2 data-[side=right]:slide-in-from-left-2 data-[side=top]:slide-in-from-bottom-2 data-[state=closed]:animate-out data-[state=closed]:fade-out-0 data-[state=closed]:zoom-out-95 data-[state=open]:animate-in data-[state=open]:fade-in-0 data-[state=open]:zoom-in-95 origin-[var(--radix-dropdown-menu-content-transform-origin)]",
|
|
33
33
|
className
|
|
34
34
|
),
|
|
35
35
|
...props
|
|
@@ -44,7 +44,7 @@ const DropdownMenuItem = React.forwardRef(({ className, inset, variant = "defaul
|
|
|
44
44
|
"data-inset": inset,
|
|
45
45
|
"data-variant": variant,
|
|
46
46
|
className: cn(
|
|
47
|
-
"
|
|
47
|
+
"ui-dropdown-menu-item [&_svg:not([class*='text-'])]:text-muted-foreground",
|
|
48
48
|
className
|
|
49
49
|
),
|
|
50
50
|
...props
|
|
@@ -57,7 +57,7 @@ const DropdownMenuLabel = React.forwardRef(({ className, inset, ...props }, ref)
|
|
|
57
57
|
ref,
|
|
58
58
|
"data-slot": "dropdown-menu-label",
|
|
59
59
|
"data-inset": inset,
|
|
60
|
-
className: cn("
|
|
60
|
+
className: cn("ui-dropdown-menu-label", className),
|
|
61
61
|
...props
|
|
62
62
|
}
|
|
63
63
|
));
|
|
@@ -67,7 +67,7 @@ const DropdownMenuSeparator = React.forwardRef(({ className, ...props }, ref) =>
|
|
|
67
67
|
{
|
|
68
68
|
ref,
|
|
69
69
|
"data-slot": "dropdown-menu-separator",
|
|
70
|
-
className: cn("
|
|
70
|
+
className: cn("ui-dropdown-menu-separator", className),
|
|
71
71
|
...props
|
|
72
72
|
}
|
|
73
73
|
));
|
|
@@ -77,14 +77,11 @@ const DropdownMenuCheckboxItem = React.forwardRef(({ className, children, checke
|
|
|
77
77
|
{
|
|
78
78
|
ref,
|
|
79
79
|
"data-slot": "dropdown-menu-checkbox-item",
|
|
80
|
-
className: cn(
|
|
81
|
-
"focus:bg-accent focus:text-accent-foreground relative flex cursor-default items-center gap-2 rounded-sm py-1.5 ps-8 pe-2 text-sm transition-colors outline-none select-none data-[disabled]:pointer-events-none data-[disabled]:opacity-50 [&_svg]:pointer-events-none [&_svg]:shrink-0",
|
|
82
|
-
className
|
|
83
|
-
),
|
|
80
|
+
className: cn("ui-dropdown-menu-checkbox-item", className),
|
|
84
81
|
checked,
|
|
85
82
|
...props,
|
|
86
83
|
children: [
|
|
87
|
-
/* @__PURE__ */ jsx("span", { className: "
|
|
84
|
+
/* @__PURE__ */ jsx("span", { className: "ui-dropdown-menu-indicator-slot", children: /* @__PURE__ */ jsx(DropdownMenuPrimitive.ItemIndicator, { children: /* @__PURE__ */ jsx(Check, { className: "ui-dropdown-menu-check", "aria-hidden": "true" }) }) }),
|
|
88
85
|
children
|
|
89
86
|
]
|
|
90
87
|
}
|
|
@@ -95,10 +92,7 @@ const DropdownMenuRadioItem = React.forwardRef(({ className, children, ...props
|
|
|
95
92
|
{
|
|
96
93
|
ref,
|
|
97
94
|
"data-slot": "dropdown-menu-radio-item",
|
|
98
|
-
className: cn(
|
|
99
|
-
"focus:bg-accent focus:text-accent-foreground data-[state=checked]:bg-primary/10 data-[state=checked]:text-primary relative flex cursor-default items-center gap-2 rounded-sm px-2.5 py-1.5 text-sm transition-colors outline-none select-none data-[disabled]:pointer-events-none data-[disabled]:opacity-50 data-[state=checked]:font-medium [&_svg]:pointer-events-none [&_svg]:shrink-0",
|
|
100
|
-
className
|
|
101
|
-
),
|
|
95
|
+
className: cn("ui-dropdown-menu-radio-item", className),
|
|
102
96
|
...props,
|
|
103
97
|
children
|
|
104
98
|
}
|
|
@@ -111,13 +105,13 @@ const DropdownMenuSubTrigger = React.forwardRef(({ className, inset, children, .
|
|
|
111
105
|
"data-slot": "dropdown-menu-sub-trigger",
|
|
112
106
|
"data-inset": inset,
|
|
113
107
|
className: cn(
|
|
114
|
-
"
|
|
108
|
+
"ui-dropdown-menu-sub-trigger [&_svg:not([class*='text-'])]:text-muted-foreground",
|
|
115
109
|
className
|
|
116
110
|
),
|
|
117
111
|
...props,
|
|
118
112
|
children: [
|
|
119
113
|
children,
|
|
120
|
-
/* @__PURE__ */ jsx(ChevronRight, { className: "
|
|
114
|
+
/* @__PURE__ */ jsx(ChevronRight, { className: "ui-dropdown-menu-sub-trigger-icon", "aria-hidden": "true" })
|
|
121
115
|
]
|
|
122
116
|
}
|
|
123
117
|
));
|
|
@@ -128,7 +122,7 @@ const DropdownMenuSubContent = React.forwardRef(({ className, ...props }, ref) =
|
|
|
128
122
|
ref,
|
|
129
123
|
"data-slot": "dropdown-menu-sub-content",
|
|
130
124
|
className: cn(
|
|
131
|
-
"
|
|
125
|
+
"ui-dropdown-menu-sub-content data-[side=bottom]:slide-in-from-top-2 data-[side=left]:slide-in-from-right-2 data-[side=right]:slide-in-from-left-2 data-[side=top]:slide-in-from-bottom-2 data-[state=closed]:animate-out data-[state=closed]:fade-out-0 data-[state=closed]:zoom-out-95 data-[state=open]:animate-in data-[state=open]:fade-in-0 data-[state=open]:zoom-in-95 origin-[var(--radix-dropdown-menu-content-transform-origin)]",
|
|
132
126
|
className
|
|
133
127
|
),
|
|
134
128
|
...props
|
|
@@ -1,12 +1,9 @@
|
|
|
1
1
|
import * as React from "react";
|
|
2
2
|
import * as MenubarPrimitive from "@radix-ui/react-menubar";
|
|
3
3
|
export declare const Menubar: React.ForwardRefExoticComponent<MenubarPrimitive.MenubarProps & React.RefAttributes<HTMLDivElement>>;
|
|
4
|
-
export declare const MenubarMenu: {
|
|
5
|
-
(
|
|
6
|
-
|
|
7
|
-
}): React.JSX.Element;
|
|
8
|
-
displayName: string;
|
|
9
|
-
};
|
|
4
|
+
export declare const MenubarMenu: (props: MenubarPrimitive.MenubarMenuProps & {
|
|
5
|
+
__scopeMenubar?: import("@radix-ui/react-context").Scope;
|
|
6
|
+
}) => React.JSX.Element;
|
|
10
7
|
export declare function MenubarTrigger(props: React.ComponentProps<typeof MenubarPrimitive.Trigger>): React.JSX.Element;
|
|
11
8
|
export declare const MenubarContent: React.ForwardRefExoticComponent<Omit<MenubarPrimitive.MenubarContentProps & React.RefAttributes<HTMLDivElement>, "ref"> & React.RefAttributes<HTMLDivElement>>;
|
|
12
9
|
export declare const MenubarItem: React.ForwardRefExoticComponent<Omit<MenubarPrimitive.MenubarItemProps & React.RefAttributes<HTMLDivElement>, "ref"> & {
|
|
@@ -1,2 +1,15 @@
|
|
|
1
|
-
/**
|
|
2
|
-
|
|
1
|
+
/**
|
|
2
|
+
* Build visible page numbers with ellipsis — Ant Design / MUI pagination style.
|
|
3
|
+
*
|
|
4
|
+
* The item count is CONSTANT wherever the current page sits. The earlier version
|
|
5
|
+
* derived the window straight from `current ± siblingCount` and let it collapse
|
|
6
|
+
* against the edges, so a 1,060-page list opened as `1 2 … 1060` — four controls
|
|
7
|
+
* with a wide empty gap, and both a bad target size and a bad sense of scale
|
|
8
|
+
* (reported 2026-08-24). Ant Design and MUI both solve this by CLAMPING the
|
|
9
|
+
* window instead of shrinking it: near an edge the window slides inward so the
|
|
10
|
+
* strip keeps its full width. Same list now opens as `1 2 3 4 5 … 1060`.
|
|
11
|
+
*
|
|
12
|
+
* Slots = `boundaryCount * 2` edges + `siblingCount * 2 + 1` around current + 2
|
|
13
|
+
* ellipsis positions. With the defaults that is 7 controls.
|
|
14
|
+
*/
|
|
15
|
+
export declare function buildPageRange(current: number, totalPages: number, siblingCount?: number, boundaryCount?: number): (number | "ellipsis")[];
|
|
@@ -1,24 +1,30 @@
|
|
|
1
|
-
function
|
|
2
|
-
|
|
3
|
-
|
|
4
|
-
|
|
5
|
-
|
|
6
|
-
|
|
7
|
-
const
|
|
8
|
-
|
|
9
|
-
const
|
|
10
|
-
const
|
|
11
|
-
const
|
|
12
|
-
|
|
13
|
-
|
|
14
|
-
|
|
15
|
-
|
|
16
|
-
|
|
17
|
-
|
|
18
|
-
|
|
19
|
-
|
|
20
|
-
|
|
21
|
-
|
|
1
|
+
function range(start, end) {
|
|
2
|
+
return end < start ? [] : Array.from({ length: end - start + 1 }, (_, i) => start + i);
|
|
3
|
+
}
|
|
4
|
+
function buildPageRange(current, totalPages, siblingCount = 1, boundaryCount = 1) {
|
|
5
|
+
if (totalPages <= 0) return [];
|
|
6
|
+
if (totalPages === 1) return [1];
|
|
7
|
+
const totalNumbers = boundaryCount * 2 + siblingCount * 2 + 3;
|
|
8
|
+
if (totalPages <= totalNumbers) return range(1, totalPages);
|
|
9
|
+
const startPages = range(1, Math.min(boundaryCount, totalPages));
|
|
10
|
+
const endPages = range(Math.max(totalPages - boundaryCount + 1, boundaryCount + 1), totalPages);
|
|
11
|
+
const siblingsStart = Math.max(
|
|
12
|
+
Math.min(current - siblingCount, totalPages - boundaryCount - siblingCount * 2 - 1),
|
|
13
|
+
boundaryCount + 2
|
|
14
|
+
);
|
|
15
|
+
const siblingsEnd = Math.min(
|
|
16
|
+
Math.max(current + siblingCount, boundaryCount + siblingCount * 2 + 2),
|
|
17
|
+
endPages.length > 0 ? endPages[0] - 2 : totalPages - 1
|
|
18
|
+
);
|
|
19
|
+
return [
|
|
20
|
+
...startPages,
|
|
21
|
+
// An ellipsis that would hide exactly ONE page is pointless — spell that page out
|
|
22
|
+
// instead (Ant/MUI do the same), which is also what keeps the count constant.
|
|
23
|
+
...siblingsStart > boundaryCount + 2 ? ["ellipsis"] : boundaryCount + 1 < totalPages - boundaryCount ? [boundaryCount + 1] : [],
|
|
24
|
+
...range(siblingsStart, siblingsEnd),
|
|
25
|
+
...siblingsEnd < totalPages - boundaryCount - 1 ? ["ellipsis"] : totalPages - boundaryCount > boundaryCount ? [totalPages - boundaryCount] : [],
|
|
26
|
+
...endPages
|
|
27
|
+
];
|
|
22
28
|
}
|
|
23
29
|
export {
|
|
24
30
|
buildPageRange
|
|
@@ -8,10 +8,10 @@ declare const PaginationLink: React.ForwardRefExoticComponent<Omit<Omit<React.De
|
|
|
8
8
|
disabled?: boolean;
|
|
9
9
|
href?: string;
|
|
10
10
|
} & React.RefAttributes<HTMLButtonElement>>;
|
|
11
|
-
declare
|
|
12
|
-
|
|
13
|
-
displayName: string;
|
|
14
|
-
}
|
|
11
|
+
declare function PaginationEllipsis({ className, ...props }: React.HTMLAttributes<HTMLSpanElement>): React.JSX.Element;
|
|
12
|
+
declare namespace PaginationEllipsis {
|
|
13
|
+
var displayName: string;
|
|
14
|
+
}
|
|
15
15
|
declare const PaginationPrevious: React.ForwardRefExoticComponent<Omit<Omit<React.DetailedHTMLProps<React.ButtonHTMLAttributes<HTMLButtonElement>, HTMLButtonElement>, "ref">, "type"> & {
|
|
16
16
|
isActive?: boolean;
|
|
17
17
|
disabled?: boolean;
|
|
@@ -142,7 +142,7 @@ function Pagination({
|
|
|
142
142
|
disabled: Boolean(disabled) || safeCurrent <= 1,
|
|
143
143
|
"aria-label": t("navigation.pagination.prev"),
|
|
144
144
|
onClick: () => go(safeCurrent - 1),
|
|
145
|
-
children: /* @__PURE__ */ jsx(ChevronLeft, {
|
|
145
|
+
children: /* @__PURE__ */ jsx(ChevronLeft, { "aria-hidden": "true" })
|
|
146
146
|
}
|
|
147
147
|
),
|
|
148
148
|
/* @__PURE__ */ jsxs("span", { className: "ui-pagination-count", children: [
|
|
@@ -159,7 +159,7 @@ function Pagination({
|
|
|
159
159
|
disabled: Boolean(disabled) || safeCurrent >= totalPages,
|
|
160
160
|
"aria-label": t("navigation.pagination.next"),
|
|
161
161
|
onClick: () => go(safeCurrent + 1),
|
|
162
|
-
children: /* @__PURE__ */ jsx(ChevronRight, {
|
|
162
|
+
children: /* @__PURE__ */ jsx(ChevronRight, { "aria-hidden": "true" })
|
|
163
163
|
}
|
|
164
164
|
)
|
|
165
165
|
] });
|