@godxjp/ui 20.1.0 → 20.2.1
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/app-provider.js +37 -21
- package/dist/app/index.d.ts +2 -0
- package/dist/app/index.js +2 -0
- package/dist/app/storage.d.ts +17 -0
- package/dist/app/storage.js +28 -0
- package/dist/components/data-display/popover.d.ts +7 -1
- package/dist/components/data-display/popover.js +4 -0
- package/dist/components/data-display/service-launcher-card.js +4 -2
- package/dist/components/data-display/table.d.ts +60 -0
- package/dist/components/data-display/table.js +8 -0
- package/dist/components/data-entry/calendar.d.ts +1 -1
- package/dist/components/data-entry/calendar.js +11 -2
- package/dist/components/feedback/dialog.js +3 -0
- package/dist/components/feedback/sheet.js +3 -0
- package/dist/components/feedback/tooltip.js +3 -0
- package/dist/components/general/button.d.ts +1 -0
- package/dist/components/general/button.js +2 -0
- package/dist/components/layout/app-launcher.d.ts +1 -1
- package/dist/components/layout/app-launcher.js +43 -10
- package/dist/components/layout/app-shell.d.ts +1 -1
- package/dist/components/layout/app-shell.js +14 -7
- package/dist/components/layout/auth-shell.d.ts +1 -1
- package/dist/components/layout/auth-shell.js +2 -0
- package/dist/components/layout/org-switcher.js +22 -2
- package/dist/components/layout/sidebar.js +2 -1
- package/dist/components/navigation/dropdown-menu.js +5 -0
- package/dist/components/ui/hover-card.js +3 -0
- package/dist/i18n/index.d.ts +1 -1
- package/dist/i18n/index.js +3 -1
- package/dist/i18n/messages/en.json +8 -1
- package/dist/i18n/messages/ja.json +8 -1
- package/dist/i18n/messages/vi.json +8 -1
- package/dist/i18n/translate.d.ts +19 -0
- package/dist/i18n/translate.js +24 -0
- package/dist/lib/overlay-portal.d.ts +18 -0
- package/dist/lib/overlay-portal.js +17 -0
- package/dist/props/components/app.prop.d.ts +13 -2
- package/dist/props/components/general.prop.d.ts +13 -0
- package/dist/props/components/layout.prop.d.ts +95 -5
- package/dist/styles/card-layout.css +10 -1
- package/dist/styles/chart-layout.css +2 -1
- package/dist/styles/control.css +5 -0
- package/dist/styles/data-display-layout.css +7 -1
- package/dist/styles/navigation-layout.css +3 -1
- package/dist/styles/shell-layout.css +496 -22
- package/dist/tokens/components/control.css +2 -1
- package/dist/tokens/components/shell.css +59 -3
- package/dist/tokens/foundation.css +2 -0
- package/docs/data-display/list-row.tsx +6 -6
- package/docs/layout/app-launcher.tsx +44 -0
- package/docs/layout/app-shell-arrangements.tsx +5 -5
- package/docs/showcase/settings-security-mfa.tsx +3 -3
- package/package.json +7 -4
- package/scripts/_agent-setup.mjs +57 -7
- package/scripts/visual-audit.mjs +45 -7
package/dist/app/app-provider.js
CHANGED
|
@@ -14,7 +14,13 @@ import {
|
|
|
14
14
|
enableLiveRelativeFormatting,
|
|
15
15
|
syncDatetimeContext
|
|
16
16
|
} from "../lib/datetime/index.js";
|
|
17
|
-
import {
|
|
17
|
+
import {
|
|
18
|
+
DEFAULT_STORAGE_KEY,
|
|
19
|
+
pickPersistedAxes,
|
|
20
|
+
readStoredPreferences,
|
|
21
|
+
resolvePersistedAxes,
|
|
22
|
+
writeStoredPreferences
|
|
23
|
+
} from "./storage.js";
|
|
18
24
|
import {
|
|
19
25
|
applyThemeAxes,
|
|
20
26
|
PREFERS_DARK_SCHEME_QUERY
|
|
@@ -105,8 +111,18 @@ function AppProvider({
|
|
|
105
111
|
fontSize,
|
|
106
112
|
scaling
|
|
107
113
|
});
|
|
114
|
+
const persistKey = Array.isArray(persist) ? [...persist].sort().join(",") : String(persist);
|
|
115
|
+
const persistedAxes = React.useMemo(
|
|
116
|
+
() => resolvePersistedAxes(persist),
|
|
117
|
+
// eslint-disable-next-line react-hooks/exhaustive-deps
|
|
118
|
+
[persistKey]
|
|
119
|
+
);
|
|
120
|
+
const commitPreferences = React.useCallback(() => {
|
|
121
|
+
if (persistedAxes.size === 0) return;
|
|
122
|
+
writeStoredPreferences(storageKey, pickPersistedAxes(prefsRef.current, persistedAxes));
|
|
123
|
+
}, [persistedAxes, storageKey]);
|
|
108
124
|
React.useEffect(() => {
|
|
109
|
-
const stored =
|
|
125
|
+
const stored = pickPersistedAxes(readStoredPreferences(storageKey), persistedAxes);
|
|
110
126
|
const nextLocale = stored.locale ?? defaultLocale;
|
|
111
127
|
const nextTimezone = stored.timezone ?? resolveDefaultTimezone(defaultTimezone, systemTimezone);
|
|
112
128
|
const nextTimeFormat = resolveInitialTimeFormat(
|
|
@@ -154,7 +170,7 @@ function AppProvider({
|
|
|
154
170
|
initialDensity,
|
|
155
171
|
initialFontSize,
|
|
156
172
|
initialScaling,
|
|
157
|
-
|
|
173
|
+
persistedAxes,
|
|
158
174
|
storageKey,
|
|
159
175
|
systemTimezone
|
|
160
176
|
]);
|
|
@@ -188,81 +204,81 @@ function AppProvider({
|
|
|
188
204
|
prefsRef.current = { ...prefsRef.current, locale: next };
|
|
189
205
|
setLocaleState(next);
|
|
190
206
|
onLocaleChange?.(next);
|
|
191
|
-
|
|
207
|
+
commitPreferences();
|
|
192
208
|
},
|
|
193
|
-
[onLocaleChange,
|
|
209
|
+
[onLocaleChange, commitPreferences]
|
|
194
210
|
);
|
|
195
211
|
const setTimezone = React.useCallback(
|
|
196
212
|
(next) => {
|
|
197
213
|
prefsRef.current = { ...prefsRef.current, timezone: next };
|
|
198
214
|
setTimezoneState(next);
|
|
199
215
|
onTimezoneChange?.(next);
|
|
200
|
-
|
|
216
|
+
commitPreferences();
|
|
201
217
|
},
|
|
202
|
-
[onTimezoneChange,
|
|
218
|
+
[onTimezoneChange, commitPreferences]
|
|
203
219
|
);
|
|
204
220
|
const setTimeFormat = React.useCallback(
|
|
205
221
|
(next) => {
|
|
206
222
|
prefsRef.current = { ...prefsRef.current, timeFormat: next };
|
|
207
223
|
setTimeFormatState(next);
|
|
208
224
|
onTimeFormatChange?.(next);
|
|
209
|
-
|
|
225
|
+
commitPreferences();
|
|
210
226
|
},
|
|
211
|
-
[onTimeFormatChange,
|
|
227
|
+
[onTimeFormatChange, commitPreferences]
|
|
212
228
|
);
|
|
213
229
|
const setDateFormat = React.useCallback(
|
|
214
230
|
(next) => {
|
|
215
231
|
prefsRef.current = { ...prefsRef.current, dateFormat: next };
|
|
216
232
|
setDateFormatState(next);
|
|
217
233
|
onDateFormatChange?.(next);
|
|
218
|
-
|
|
234
|
+
commitPreferences();
|
|
219
235
|
},
|
|
220
|
-
[onDateFormatChange,
|
|
236
|
+
[onDateFormatChange, commitPreferences]
|
|
221
237
|
);
|
|
222
238
|
const setTheme = React.useCallback(
|
|
223
239
|
(next) => {
|
|
224
240
|
prefsRef.current = { ...prefsRef.current, theme: next };
|
|
225
241
|
setThemeState(next);
|
|
226
242
|
onThemeChange?.(next);
|
|
227
|
-
|
|
243
|
+
commitPreferences();
|
|
228
244
|
},
|
|
229
|
-
[onThemeChange,
|
|
245
|
+
[onThemeChange, commitPreferences]
|
|
230
246
|
);
|
|
231
247
|
const setBrand = React.useCallback(
|
|
232
248
|
(next) => {
|
|
233
249
|
prefsRef.current = { ...prefsRef.current, brand: next };
|
|
234
250
|
setBrandState(next);
|
|
235
251
|
onBrandChange?.(next);
|
|
236
|
-
|
|
252
|
+
commitPreferences();
|
|
237
253
|
},
|
|
238
|
-
[onBrandChange,
|
|
254
|
+
[onBrandChange, commitPreferences]
|
|
239
255
|
);
|
|
240
256
|
const setDensity = React.useCallback(
|
|
241
257
|
(next) => {
|
|
242
258
|
prefsRef.current = { ...prefsRef.current, density: next };
|
|
243
259
|
setDensityState(next);
|
|
244
260
|
onDensityChange?.(next);
|
|
245
|
-
|
|
261
|
+
commitPreferences();
|
|
246
262
|
},
|
|
247
|
-
[onDensityChange,
|
|
263
|
+
[onDensityChange, commitPreferences]
|
|
248
264
|
);
|
|
249
265
|
const setFontSize = React.useCallback(
|
|
250
266
|
(next) => {
|
|
251
267
|
prefsRef.current = { ...prefsRef.current, fontSize: next };
|
|
252
268
|
setFontSizeState(next);
|
|
253
269
|
onFontSizeChange?.(next);
|
|
254
|
-
|
|
270
|
+
commitPreferences();
|
|
255
271
|
},
|
|
256
|
-
[onFontSizeChange,
|
|
272
|
+
[onFontSizeChange, commitPreferences]
|
|
257
273
|
);
|
|
258
274
|
const setScaling = React.useCallback(
|
|
259
275
|
(next) => {
|
|
260
276
|
prefsRef.current = { ...prefsRef.current, scaling: next };
|
|
261
277
|
setScalingState(next);
|
|
262
278
|
onScalingChange?.(next);
|
|
263
|
-
|
|
279
|
+
commitPreferences();
|
|
264
280
|
},
|
|
265
|
-
[onScalingChange,
|
|
281
|
+
[onScalingChange, commitPreferences]
|
|
266
282
|
);
|
|
267
283
|
const requestHeaders = React.useMemo(
|
|
268
284
|
() => buildRequestHeaders(locale, timezone, timeFormat, dateFormat),
|
package/dist/app/index.d.ts
CHANGED
|
@@ -12,3 +12,5 @@ export { AppProvider, useAppContext, useOptionalAppContext, useAppLocale, useApp
|
|
|
12
12
|
export { useFormatting, useDateTime } from "./use-formatting.js";
|
|
13
13
|
export { syncDatetimeContext, getDatetimeContext, formatDate, isFormatDateValue, detectFormatDateKind, formatAppDate, formatAppDateTime, formatAppTime, formatAppDateLong, formatAppRelative, formatCalendarDate, formatTimeOfDay, parseDateInput, normalizeHhmm, isValidHhmm, type FormatDateOptions, type FormatDateKind, type FormatDatetimeOptions, } from "../lib/datetime/index.js";
|
|
14
14
|
export { useTranslation, usePickerLocales } from "../i18n/use-translation.js";
|
|
15
|
+
export { OverlayPortalProvider } from "../lib/overlay-portal.js";
|
|
16
|
+
export type { OverlayPortalProviderProps } from "../lib/overlay-portal.js";
|
package/dist/app/index.js
CHANGED
|
@@ -36,8 +36,10 @@ import {
|
|
|
36
36
|
isValidHhmm
|
|
37
37
|
} from "../lib/datetime/index.js";
|
|
38
38
|
import { useTranslation, usePickerLocales } from "../i18n/use-translation.js";
|
|
39
|
+
import { OverlayPortalProvider } from "../lib/overlay-portal.js";
|
|
39
40
|
export {
|
|
40
41
|
AppProvider,
|
|
42
|
+
OverlayPortalProvider,
|
|
41
43
|
detectFormatDateKind,
|
|
42
44
|
formatAppDate,
|
|
43
45
|
formatAppDateLong,
|
package/dist/app/storage.d.ts
CHANGED
|
@@ -14,6 +14,23 @@ export type StoredAppPreferences = {
|
|
|
14
14
|
/** Continuous global size multiplier; `null` defers to the density preset. */
|
|
15
15
|
scaling?: number | null;
|
|
16
16
|
};
|
|
17
|
+
/**
|
|
18
|
+
* The axes a viewer's preferences are made of — the keys of {@link StoredAppPreferences}.
|
|
19
|
+
*
|
|
20
|
+
* They do NOT share an owner. `theme`, `density`, `fontSize`, `scaling` and `brand` are the
|
|
21
|
+
* viewer's, and belong in this browser. `locale`, `timezone`, `timeFormat` and `dateFormat` are
|
|
22
|
+
* frequently the SERVER's — resolved per request from a cookie, an account row or an Accept-Language
|
|
23
|
+
* header — and a copy in local storage then wins over the value the server just sent, because
|
|
24
|
+
* storage is read after the props. That is why `persist` takes a LIST as well as a boolean: one
|
|
25
|
+
* flag for axes with two different owners forces an all-or-nothing choice, and the consumer that
|
|
26
|
+
* hits it turns persistence off entirely and loses the viewer's theme with it.
|
|
27
|
+
*/
|
|
28
|
+
export declare const APP_PREFERENCE_AXES: readonly ["locale", "timezone", "timeFormat", "dateFormat", "theme", "brand", "density", "fontSize", "scaling"];
|
|
29
|
+
export type AppPreferenceAxis = (typeof APP_PREFERENCE_AXES)[number];
|
|
30
|
+
/** `true` → every axis, `false` → none, a list → exactly those. */
|
|
31
|
+
export declare function resolvePersistedAxes(persist: boolean | readonly AppPreferenceAxis[]): ReadonlySet<AppPreferenceAxis>;
|
|
32
|
+
/** The subset of `preferences` on the given axes; the rest are dropped, not set to undefined. */
|
|
33
|
+
export declare function pickPersistedAxes(preferences: StoredAppPreferences, axes: ReadonlySet<AppPreferenceAxis>): StoredAppPreferences;
|
|
17
34
|
export declare function readStoredPreferences(storageKey: string): StoredAppPreferences;
|
|
18
35
|
export declare function writeStoredPreferences(storageKey: string, preferences: StoredAppPreferences): void;
|
|
19
36
|
export { DEFAULT_STORAGE_KEY };
|
package/dist/app/storage.js
CHANGED
|
@@ -8,6 +8,31 @@ import {
|
|
|
8
8
|
isAppTheme
|
|
9
9
|
} from "./theme-axes.js";
|
|
10
10
|
const DEFAULT_STORAGE_KEY = "godxjp.app";
|
|
11
|
+
const APP_PREFERENCE_AXES = [
|
|
12
|
+
"locale",
|
|
13
|
+
"timezone",
|
|
14
|
+
"timeFormat",
|
|
15
|
+
"dateFormat",
|
|
16
|
+
"theme",
|
|
17
|
+
"brand",
|
|
18
|
+
"density",
|
|
19
|
+
"fontSize",
|
|
20
|
+
"scaling"
|
|
21
|
+
];
|
|
22
|
+
function resolvePersistedAxes(persist) {
|
|
23
|
+
if (persist === true) return new Set(APP_PREFERENCE_AXES);
|
|
24
|
+
if (persist === false) return /* @__PURE__ */ new Set();
|
|
25
|
+
return new Set(persist);
|
|
26
|
+
}
|
|
27
|
+
function pickPersistedAxes(preferences, axes) {
|
|
28
|
+
const out = {};
|
|
29
|
+
for (const axis of APP_PREFERENCE_AXES) {
|
|
30
|
+
if (axes.has(axis) && preferences[axis] !== void 0) {
|
|
31
|
+
out[axis] = preferences[axis];
|
|
32
|
+
}
|
|
33
|
+
}
|
|
34
|
+
return out;
|
|
35
|
+
}
|
|
11
36
|
function readStoredPreferences(storageKey) {
|
|
12
37
|
if (typeof window === "undefined") return {};
|
|
13
38
|
try {
|
|
@@ -37,7 +62,10 @@ function writeStoredPreferences(storageKey, preferences) {
|
|
|
37
62
|
}
|
|
38
63
|
}
|
|
39
64
|
export {
|
|
65
|
+
APP_PREFERENCE_AXES,
|
|
40
66
|
DEFAULT_STORAGE_KEY,
|
|
67
|
+
pickPersistedAxes,
|
|
41
68
|
readStoredPreferences,
|
|
69
|
+
resolvePersistedAxes,
|
|
42
70
|
writeStoredPreferences
|
|
43
71
|
};
|
|
@@ -34,6 +34,12 @@ type PopoverContentFlush = {
|
|
|
34
34
|
flush?: FlushProp;
|
|
35
35
|
};
|
|
36
36
|
interface PopoverContentProps extends React.ComponentPropsWithRef<"div">, PopoverContentFlush {
|
|
37
|
+
/**
|
|
38
|
+
* Render THIS panel somewhere other than the default. Almost always unnecessary: mounting the
|
|
39
|
+
* whole tree in a shadow root is what `OverlayPortalProvider` is for, and it moves every overlay
|
|
40
|
+
* at once. Reach for this only to place one panel differently from the rest.
|
|
41
|
+
*/
|
|
42
|
+
portalContainer?: Element;
|
|
37
43
|
/** Cạnh của trigger mà panel bám vào. */
|
|
38
44
|
side?: Side;
|
|
39
45
|
/** Canh panel theo cạnh của trigger. */
|
|
@@ -67,7 +73,7 @@ interface PopoverContentProps extends React.ComponentPropsWithRef<"div">, Popove
|
|
|
67
73
|
*/
|
|
68
74
|
onCloseAutoFocus?: (event: Event) => void;
|
|
69
75
|
}
|
|
70
|
-
export declare function PopoverContent({ className, style, children, ref, flush, side, align, sideOffset, alignOffset, avoidCollisions, collisionPadding, sticky: _sticky, hideWhenDetached: _hideWhenDetached, forceMount: _forceMount, onOpenAutoFocus, onCloseAutoFocus, ...props }: PopoverContentProps): React.JSX.Element;
|
|
76
|
+
export declare function PopoverContent({ className, style, children, ref, flush, side, align, sideOffset, alignOffset, avoidCollisions, collisionPadding, sticky: _sticky, hideWhenDetached: _hideWhenDetached, forceMount: _forceMount, onOpenAutoFocus, onCloseAutoFocus, portalContainer, ...props }: PopoverContentProps): React.JSX.Element;
|
|
71
77
|
export declare const PopoverHeader: ({ className, ...props }: React.HTMLAttributes<HTMLDivElement>) => React.JSX.Element;
|
|
72
78
|
export declare const PopoverTitle: ({ className, id, ...props }: React.HTMLAttributes<HTMLDivElement>) => React.JSX.Element;
|
|
73
79
|
export declare const PopoverDescription: ({ className, id, ...props }: React.HTMLAttributes<HTMLParagraphElement>) => React.JSX.Element;
|
|
@@ -1,5 +1,6 @@
|
|
|
1
1
|
"use client";
|
|
2
2
|
import { jsx } from "react/jsx-runtime";
|
|
3
|
+
import { useOverlayPortalContainer } from "../../lib/overlay-portal.js";
|
|
3
4
|
import * as React from "react";
|
|
4
5
|
import { chain, mergeRefs } from "@react-aria/utils";
|
|
5
6
|
import { Popover as AriaPopover } from "react-aria-components";
|
|
@@ -142,6 +143,7 @@ function PopoverContent({
|
|
|
142
143
|
forceMount: _forceMount,
|
|
143
144
|
onOpenAutoFocus,
|
|
144
145
|
onCloseAutoFocus,
|
|
146
|
+
portalContainer,
|
|
145
147
|
...props
|
|
146
148
|
}) {
|
|
147
149
|
const root = usePopoverRoot("PopoverContent");
|
|
@@ -176,9 +178,11 @@ function PopoverContent({
|
|
|
176
178
|
document.addEventListener("pointerdown", onPointerDown);
|
|
177
179
|
return () => document.removeEventListener("pointerdown", onPointerDown);
|
|
178
180
|
}, [open, setOpen, triggerRef]);
|
|
181
|
+
const overlayPortalContainer = useOverlayPortalContainer(portalContainer);
|
|
179
182
|
return /* @__PURE__ */ jsx(
|
|
180
183
|
AriaPopover,
|
|
181
184
|
{
|
|
185
|
+
UNSTABLE_portalContainer: overlayPortalContainer,
|
|
182
186
|
isOpen: root.open,
|
|
183
187
|
onOpenChange: root.setOpen,
|
|
184
188
|
isNonModal: root.isNonModal,
|
|
@@ -31,8 +31,10 @@ const ServiceLauncherCard = React.forwardRef(
|
|
|
31
31
|
...props,
|
|
32
32
|
children: /* @__PURE__ */ jsxs(CardContent, { solo: true, children: [
|
|
33
33
|
/* @__PURE__ */ jsxs("div", { "data-slot": "service-launcher-heading", children: [
|
|
34
|
-
/* @__PURE__ */
|
|
35
|
-
|
|
34
|
+
/* @__PURE__ */ jsxs("div", { "data-slot": "service-launcher-identity", children: [
|
|
35
|
+
/* @__PURE__ */ jsx("span", { "data-slot": "service-launcher-icon", "aria-hidden": "true", children: /* @__PURE__ */ jsx(Icon, {}) }),
|
|
36
|
+
/* @__PURE__ */ jsx(Heading, { "data-slot": "service-launcher-title", children: title })
|
|
37
|
+
] }),
|
|
36
38
|
statusLabel != null ? /* @__PURE__ */ jsx(Badge, { tone: statusTone, "data-slot": "service-launcher-status", children: statusLabel }) : null
|
|
37
39
|
] }),
|
|
38
40
|
description != null ? /* @__PURE__ */ jsx("div", { "data-slot": "service-launcher-description", children: description }) : null,
|
|
@@ -18,6 +18,36 @@ export type TableProps = React.HTMLAttributes<HTMLTableElement> & {
|
|
|
18
18
|
* table exactly as it is.
|
|
19
19
|
*/
|
|
20
20
|
preset?: TablePresetProp;
|
|
21
|
+
/**
|
|
22
|
+
* PER-INSTANCE column measures for `preset="action-collection"`, in place of re-pointing its
|
|
23
|
+
* `--table-action-collection-*` knobs from a consumer stylesheet.
|
|
24
|
+
*
|
|
25
|
+
* Those knobs are global by design, and that is exactly the problem: two collections on the same
|
|
26
|
+
* screen do not share a column budget. A console that widened `actions` globally so a Japanese
|
|
27
|
+
* status badge would stop breaking to one character per line — an SC 1.4.10 reflow failure —
|
|
28
|
+
* collapsed a sibling table's name column to ~15px in the same change. The only way out was a
|
|
29
|
+
* scoped class in consumer CSS, and the comment that shipped with it said so: "until the package
|
|
30
|
+
* can express a per-table measure, the retune stays on the collection needing it".
|
|
31
|
+
*
|
|
32
|
+
* Emitted as inline custom properties, the same contract `Flex width` uses for a call-site
|
|
33
|
+
* measurement: the value is a raw length the design system cannot know, so it rides in `style`
|
|
34
|
+
* and leaves `data-column-widths` on the DOM so each one stays countable.
|
|
35
|
+
*/
|
|
36
|
+
columnWidths?: {
|
|
37
|
+
/** `--table-action-collection-actions-width` — the row-action column above the collapse step. */
|
|
38
|
+
actions?: string;
|
|
39
|
+
/** `--table-action-collection-actions-width-compact` — the same column below it. */
|
|
40
|
+
actionsCompact?: string;
|
|
41
|
+
/** `--table-action-collection-meta-width-compact` — a `meta`-priority column below the step. */
|
|
42
|
+
metaCompact?: string;
|
|
43
|
+
/**
|
|
44
|
+
* `--table-action-collection-min-inline-size-compact` — the legibility FLOOR the compact tier
|
|
45
|
+
* keeps before the wrapper scrolls. The preset sizes its compact tier for one column per
|
|
46
|
+
* priority; a collection carrying several of the same priority needs a wider floor or its
|
|
47
|
+
* free-text column is squeezed toward zero.
|
|
48
|
+
*/
|
|
49
|
+
minInlineSizeCompact?: string;
|
|
50
|
+
};
|
|
21
51
|
/** Defaults to `"sm"` (40rem). Ignored while `preset` is `"default"`. */
|
|
22
52
|
collapseBelow?: BreakpointProp;
|
|
23
53
|
};
|
|
@@ -39,6 +69,36 @@ export declare const Table: React.ForwardRefExoticComponent<React.HTMLAttributes
|
|
|
39
69
|
* table exactly as it is.
|
|
40
70
|
*/
|
|
41
71
|
preset?: TablePresetProp;
|
|
72
|
+
/**
|
|
73
|
+
* PER-INSTANCE column measures for `preset="action-collection"`, in place of re-pointing its
|
|
74
|
+
* `--table-action-collection-*` knobs from a consumer stylesheet.
|
|
75
|
+
*
|
|
76
|
+
* Those knobs are global by design, and that is exactly the problem: two collections on the same
|
|
77
|
+
* screen do not share a column budget. A console that widened `actions` globally so a Japanese
|
|
78
|
+
* status badge would stop breaking to one character per line — an SC 1.4.10 reflow failure —
|
|
79
|
+
* collapsed a sibling table's name column to ~15px in the same change. The only way out was a
|
|
80
|
+
* scoped class in consumer CSS, and the comment that shipped with it said so: "until the package
|
|
81
|
+
* can express a per-table measure, the retune stays on the collection needing it".
|
|
82
|
+
*
|
|
83
|
+
* Emitted as inline custom properties, the same contract `Flex width` uses for a call-site
|
|
84
|
+
* measurement: the value is a raw length the design system cannot know, so it rides in `style`
|
|
85
|
+
* and leaves `data-column-widths` on the DOM so each one stays countable.
|
|
86
|
+
*/
|
|
87
|
+
columnWidths?: {
|
|
88
|
+
/** `--table-action-collection-actions-width` — the row-action column above the collapse step. */
|
|
89
|
+
actions?: string;
|
|
90
|
+
/** `--table-action-collection-actions-width-compact` — the same column below it. */
|
|
91
|
+
actionsCompact?: string;
|
|
92
|
+
/** `--table-action-collection-meta-width-compact` — a `meta`-priority column below the step. */
|
|
93
|
+
metaCompact?: string;
|
|
94
|
+
/**
|
|
95
|
+
* `--table-action-collection-min-inline-size-compact` — the legibility FLOOR the compact tier
|
|
96
|
+
* keeps before the wrapper scrolls. The preset sizes its compact tier for one column per
|
|
97
|
+
* priority; a collection carrying several of the same priority needs a wider floor or its
|
|
98
|
+
* free-text column is squeezed toward zero.
|
|
99
|
+
*/
|
|
100
|
+
minInlineSizeCompact?: string;
|
|
101
|
+
};
|
|
42
102
|
/** Defaults to `"sm"` (40rem). Ignored while `preset` is `"default"`. */
|
|
43
103
|
collapseBelow?: BreakpointProp;
|
|
44
104
|
} & React.RefAttributes<HTMLTableElement>>;
|
|
@@ -9,6 +9,7 @@ const Table = React.forwardRef(
|
|
|
9
9
|
bordered = false,
|
|
10
10
|
preset = "default",
|
|
11
11
|
collapseBelow = "sm",
|
|
12
|
+
columnWidths,
|
|
12
13
|
...props
|
|
13
14
|
}, ref) => (
|
|
14
15
|
// A table wider than its container scrolls horizontally in this wrapper; keep it
|
|
@@ -27,6 +28,13 @@ const Table = React.forwardRef(
|
|
|
27
28
|
),
|
|
28
29
|
"data-preset": preset === "default" ? void 0 : preset,
|
|
29
30
|
"data-collapse-below": preset === "default" ? void 0 : collapseBelow,
|
|
31
|
+
"data-column-widths": columnWidths ? "" : void 0,
|
|
32
|
+
style: columnWidths ? {
|
|
33
|
+
"--table-action-collection-actions-width": columnWidths.actions,
|
|
34
|
+
"--table-action-collection-actions-width-compact": columnWidths.actionsCompact,
|
|
35
|
+
"--table-action-collection-meta-width-compact": columnWidths.metaCompact,
|
|
36
|
+
"--table-action-collection-min-inline-size-compact": columnWidths.minInlineSizeCompact
|
|
37
|
+
} : void 0,
|
|
30
38
|
...scrollable ? { tabIndex: 0 } : {},
|
|
31
39
|
children: /* @__PURE__ */ jsx(
|
|
32
40
|
"table",
|
|
@@ -1,4 +1,4 @@
|
|
|
1
1
|
import * as React from "react";
|
|
2
2
|
import type { CalendarProp } from "../../props/components/data-entry.prop.js";
|
|
3
3
|
export type { CalendarProp, CalendarProp as CalendarProps, CalendarCellRenderProp, CalendarFooterProp, } from "../../props/components/data-entry.prop.js";
|
|
4
|
-
export declare function Calendar({ className, classNames, showOutsideDays, "aria-label": ariaLabel, labels, showToday, showClose, onClose, footer, width, bordered, cellRender, month: monthProp, onMonthChange, ...props }: CalendarProp): React.JSX.Element;
|
|
4
|
+
export declare function Calendar({ className, classNames, showOutsideDays, "aria-label": ariaLabel, labels, showToday, showClose, onClose, footer, width, bordered, cellRender, month: monthProp, onMonthChange, locale: localeProp, ...props }: CalendarProp): React.JSX.Element;
|
|
@@ -3,7 +3,7 @@ import { Fragment, jsx, jsxs } from "react/jsx-runtime";
|
|
|
3
3
|
import * as React from "react";
|
|
4
4
|
import { ChevronDown, ChevronLeft, ChevronRight, ChevronUp } from "lucide-react";
|
|
5
5
|
import { DayButton, DayPicker, dateMatchModifiers } from "react-day-picker";
|
|
6
|
-
import { useTranslation } from "../../i18n/use-translation.js";
|
|
6
|
+
import { usePickerLocales, useTranslation } from "../../i18n/use-translation.js";
|
|
7
7
|
import { cn } from "../../lib/utils.js";
|
|
8
8
|
import { controlIconSmClass } from "../../lib/control-styles.js";
|
|
9
9
|
import { Button, buttonVariants } from "../general/button.js";
|
|
@@ -26,9 +26,11 @@ function Calendar({
|
|
|
26
26
|
cellRender,
|
|
27
27
|
month: monthProp,
|
|
28
28
|
onMonthChange,
|
|
29
|
+
locale: localeProp,
|
|
29
30
|
...props
|
|
30
31
|
}) {
|
|
31
32
|
const { t } = useTranslation();
|
|
33
|
+
const { dayPickerLocale } = usePickerLocales(localeProp);
|
|
32
34
|
const [month, setMonth] = React.useState(monthProp ?? props.defaultMonth);
|
|
33
35
|
const today = startOfDay(props.today ?? /* @__PURE__ */ new Date());
|
|
34
36
|
const todayDisabled = props.startMonth != null && today < startOfMonth(props.startMonth) || props.endMonth != null && today > endOfMonth(props.endMonth) || props.disabled != null && dateMatchModifiers(today, props.disabled);
|
|
@@ -68,6 +70,7 @@ function Calendar({
|
|
|
68
70
|
return /* @__PURE__ */ jsx(
|
|
69
71
|
DayPicker,
|
|
70
72
|
{
|
|
73
|
+
locale: dayPickerLocale,
|
|
71
74
|
showOutsideDays,
|
|
72
75
|
"aria-label": ariaLabel,
|
|
73
76
|
month: showToday ? monthProp ?? month : monthProp,
|
|
@@ -78,7 +81,13 @@ function Calendar({
|
|
|
78
81
|
footer: footer ?? actions,
|
|
79
82
|
labels: {
|
|
80
83
|
...labels,
|
|
81
|
-
|
|
84
|
+
/*
|
|
85
|
+
* LOCALIZED, like every other string this component renders. It was an English literal
|
|
86
|
+
* built by template — so a Japanese calendar announced its own month controls as "Calendar
|
|
87
|
+
* navigation" while the two buttons INSIDE that container said 前の月へ and 次の月へ. Nothing
|
|
88
|
+
* failed and nothing warned; the only reader affected was the one using a screen reader.
|
|
89
|
+
*/
|
|
90
|
+
labelNav: labels?.labelNav ?? (() => t("dataEntry.calendar.nav", { label: ariaLabel ?? t("dataEntry.calendar.name") }))
|
|
82
91
|
},
|
|
83
92
|
className: cn("ui-calendar", className),
|
|
84
93
|
"data-width": width === "full" ? "full" : void 0,
|
|
@@ -1,5 +1,6 @@
|
|
|
1
1
|
"use client";
|
|
2
2
|
import { Fragment, jsx, jsxs } from "react/jsx-runtime";
|
|
3
|
+
import { useOverlayPortalContainer } from "../../lib/overlay-portal.js";
|
|
3
4
|
import * as React from "react";
|
|
4
5
|
import { chain, mergeRefs } from "@react-aria/utils";
|
|
5
6
|
import { Dialog as RacDialog, Modal, ModalOverlay } from "react-aria-components";
|
|
@@ -58,9 +59,11 @@ function DialogShell({
|
|
|
58
59
|
const labels = React.useMemo(() => ({ titleId, descriptionId }), [titleId, descriptionId]);
|
|
59
60
|
const dataState = state.isOpen ? "open" : "closed";
|
|
60
61
|
useOverlayCloseFocus(state.isOpen, onCloseAutoFocus);
|
|
62
|
+
const overlayPortalContainer = useOverlayPortalContainer();
|
|
61
63
|
return /* @__PURE__ */ jsx(
|
|
62
64
|
ModalOverlay,
|
|
63
65
|
{
|
|
66
|
+
UNSTABLE_portalContainer: overlayPortalContainer,
|
|
64
67
|
isOpen: state.isOpen,
|
|
65
68
|
onOpenChange: state.setOpen,
|
|
66
69
|
isDismissable,
|
|
@@ -1,5 +1,6 @@
|
|
|
1
1
|
"use client";
|
|
2
2
|
import { Fragment, jsx, jsxs } from "react/jsx-runtime";
|
|
3
|
+
import { useOverlayPortalContainer } from "../../lib/overlay-portal.js";
|
|
3
4
|
import * as React from "react";
|
|
4
5
|
import { chain, mergeRefs } from "@react-aria/utils";
|
|
5
6
|
import { Dialog as RacDialog, Modal, ModalOverlay } from "react-aria-components";
|
|
@@ -152,9 +153,11 @@ function SheetContent({
|
|
|
152
153
|
const mergedStyle = widthSet ? { ...style, ["--sheet-width"]: toCssLength(width) } : style;
|
|
153
154
|
const dataState = state.isOpen ? "open" : "closed";
|
|
154
155
|
useOverlayCloseFocus(state.isOpen);
|
|
156
|
+
const overlayPortalContainer = useOverlayPortalContainer();
|
|
155
157
|
return /* @__PURE__ */ jsx(
|
|
156
158
|
ModalOverlay,
|
|
157
159
|
{
|
|
160
|
+
UNSTABLE_portalContainer: overlayPortalContainer,
|
|
158
161
|
isOpen: state.isOpen,
|
|
159
162
|
onOpenChange: state.setOpen,
|
|
160
163
|
isDismissable: true,
|
|
@@ -1,5 +1,6 @@
|
|
|
1
1
|
"use client";
|
|
2
2
|
import { jsx } from "react/jsx-runtime";
|
|
3
|
+
import { useOverlayPortalContainer } from "../../lib/overlay-portal.js";
|
|
3
4
|
import * as React from "react";
|
|
4
5
|
import { mergeRefs } from "@react-aria/utils";
|
|
5
6
|
import {
|
|
@@ -74,9 +75,11 @@ function TooltipContent({
|
|
|
74
75
|
forceMount: _forceMount,
|
|
75
76
|
...props
|
|
76
77
|
}) {
|
|
78
|
+
const overlayPortalContainer = useOverlayPortalContainer();
|
|
77
79
|
return /* @__PURE__ */ jsx(
|
|
78
80
|
AriaTooltip,
|
|
79
81
|
{
|
|
82
|
+
UNSTABLE_portalContainer: overlayPortalContainer,
|
|
80
83
|
placement: toPlacement(side, align),
|
|
81
84
|
offset: sideOffset,
|
|
82
85
|
crossOffset: alignOffset,
|
|
@@ -10,6 +10,7 @@ export declare const Button: React.ForwardRefExoticComponent<React.ButtonHTMLAtt
|
|
|
10
10
|
size?: import("../../props/index.js").ButtonSizeProp;
|
|
11
11
|
shape?: import("../../props/index.js").ShapeProp;
|
|
12
12
|
fullWidth?: boolean;
|
|
13
|
+
fill?: boolean;
|
|
13
14
|
wrap?: boolean;
|
|
14
15
|
align?: import("../../props/index.js").TextAlignProp;
|
|
15
16
|
asChild?: import("../../props/index.js").AsChildProp;
|
|
@@ -56,6 +56,7 @@ const Button = React.forwardRef(
|
|
|
56
56
|
size,
|
|
57
57
|
shape,
|
|
58
58
|
fullWidth = false,
|
|
59
|
+
fill = false,
|
|
59
60
|
wrap = false,
|
|
60
61
|
align = "center",
|
|
61
62
|
asChild = false,
|
|
@@ -87,6 +88,7 @@ const Button = React.forwardRef(
|
|
|
87
88
|
"data-size": size ?? "default",
|
|
88
89
|
"data-shape": shape ?? "default",
|
|
89
90
|
"data-full-width": fullWidth ? "" : void 0,
|
|
91
|
+
"data-fill": fill ? "" : void 0,
|
|
90
92
|
"data-wrap": wrap ? "" : void 0,
|
|
91
93
|
"data-align": align === "center" ? void 0 : align,
|
|
92
94
|
"data-loading": isLoading ? "" : void 0,
|
|
@@ -31,4 +31,4 @@ type DataAttributes = {
|
|
|
31
31
|
* single product where switching workspace is constant enough to be worth permanent screen width
|
|
32
32
|
* (Slack). Shipping both puts one scope in two places and makes neither authoritative.
|
|
33
33
|
*/
|
|
34
|
-
export declare function AppLauncher({ apps, groups, labels, columns, linkComponent, loading, error, onRetry, responsive, open, onOpenChange, className, ...rest }: AppLauncherProp & Pick<React.ComponentPropsWithoutRef<"button">, "id"> & DataAttributes): React.JSX.Element;
|
|
34
|
+
export declare function AppLauncher({ apps, groups, labels, columns, linkComponent, loading, error, onRetry, responsive, appearance, side, align, open, onOpenChange, className, ...rest }: AppLauncherProp & Pick<React.ComponentPropsWithoutRef<"button">, "id"> & DataAttributes): React.JSX.Element;
|
|
@@ -4,6 +4,13 @@ import * as React from "react";
|
|
|
4
4
|
import { Grip, Loader2, RotateCcw } from "lucide-react";
|
|
5
5
|
import { cn } from "../../lib/utils.js";
|
|
6
6
|
import { Popover, PopoverContent, PopoverTrigger } from "../data-display/popover.js";
|
|
7
|
+
import {
|
|
8
|
+
Dialog,
|
|
9
|
+
DialogContent,
|
|
10
|
+
DialogHeader,
|
|
11
|
+
DialogTitle,
|
|
12
|
+
DialogTrigger
|
|
13
|
+
} from "../feedback/dialog.js";
|
|
7
14
|
import {
|
|
8
15
|
Sheet,
|
|
9
16
|
SheetBody,
|
|
@@ -154,6 +161,9 @@ function AppLauncher({
|
|
|
154
161
|
error,
|
|
155
162
|
onRetry,
|
|
156
163
|
responsive = "auto",
|
|
164
|
+
appearance = "bar",
|
|
165
|
+
side,
|
|
166
|
+
align,
|
|
157
167
|
open,
|
|
158
168
|
onOpenChange,
|
|
159
169
|
className,
|
|
@@ -173,18 +183,16 @@ function AppLauncher({
|
|
|
173
183
|
);
|
|
174
184
|
const compactViewport = useSheetResponsiveMode("auto") === "bottom";
|
|
175
185
|
const sheet = responsive === "sheet" || responsive === "auto" && compactViewport;
|
|
186
|
+
const launchpad = responsive === "fullscreen";
|
|
176
187
|
const close = React.useCallback(() => {
|
|
177
188
|
setOpen(false);
|
|
178
189
|
}, [setOpen]);
|
|
179
|
-
const
|
|
180
|
-
|
|
181
|
-
|
|
182
|
-
|
|
183
|
-
|
|
184
|
-
|
|
185
|
-
children: /* @__PURE__ */ jsx(Grip, { "aria-hidden": "true" })
|
|
186
|
-
}
|
|
187
|
-
);
|
|
190
|
+
const triggerProps = {
|
|
191
|
+
className: cn("ui-app-launcher-trigger", className),
|
|
192
|
+
"aria-label": labels.trigger,
|
|
193
|
+
...rest
|
|
194
|
+
};
|
|
195
|
+
const trigger = appearance === "bar" ? /* @__PURE__ */ jsx(TopbarItem, { ...triggerProps, children: /* @__PURE__ */ jsx(Grip, { "aria-hidden": "true" }) }) : /* @__PURE__ */ jsx(Button, { variant: "ghost", size: "icon-sm", ...triggerProps, children: /* @__PURE__ */ jsx(Grip, { "aria-hidden": "true" }) });
|
|
188
196
|
const panel = /* @__PURE__ */ jsx(
|
|
189
197
|
AppLauncherPanel,
|
|
190
198
|
{
|
|
@@ -199,6 +207,22 @@ function AppLauncher({
|
|
|
199
207
|
close
|
|
200
208
|
}
|
|
201
209
|
);
|
|
210
|
+
if (launchpad) {
|
|
211
|
+
return /* @__PURE__ */ jsxs(Dialog, { open: resolvedOpen, onOpenChange: setOpen, children: [
|
|
212
|
+
/* @__PURE__ */ jsx(DialogTrigger, { asChild: true, children: trigger }),
|
|
213
|
+
/* @__PURE__ */ jsxs(
|
|
214
|
+
DialogContent,
|
|
215
|
+
{
|
|
216
|
+
className: "ui-app-launcher-launchpad",
|
|
217
|
+
overlayClassName: "ui-app-launcher-launchpad-overlay",
|
|
218
|
+
children: [
|
|
219
|
+
/* @__PURE__ */ jsx(DialogHeader, { children: /* @__PURE__ */ jsx(DialogTitle, { children: labels.title }) }),
|
|
220
|
+
panel
|
|
221
|
+
]
|
|
222
|
+
}
|
|
223
|
+
)
|
|
224
|
+
] });
|
|
225
|
+
}
|
|
202
226
|
if (sheet) {
|
|
203
227
|
return /* @__PURE__ */ jsxs(Sheet, { open: resolvedOpen, onOpenChange: setOpen, children: [
|
|
204
228
|
/* @__PURE__ */ jsx(SheetTrigger, { asChild: true, children: trigger }),
|
|
@@ -220,7 +244,16 @@ function AppLauncher({
|
|
|
220
244
|
}
|
|
221
245
|
return /* @__PURE__ */ jsxs(Popover, { open: resolvedOpen, onOpenChange: setOpen, children: [
|
|
222
246
|
/* @__PURE__ */ jsx(PopoverTrigger, { asChild: true, children: trigger }),
|
|
223
|
-
/* @__PURE__ */ jsx(
|
|
247
|
+
/* @__PURE__ */ jsx(
|
|
248
|
+
PopoverContent,
|
|
249
|
+
{
|
|
250
|
+
side: side ?? (appearance === "bar" ? "bottom" : "right"),
|
|
251
|
+
align: align ?? (appearance === "bar" ? "end" : "start"),
|
|
252
|
+
className: "ui-app-launcher-popover",
|
|
253
|
+
"aria-label": labels.title,
|
|
254
|
+
children: panel
|
|
255
|
+
}
|
|
256
|
+
)
|
|
224
257
|
] });
|
|
225
258
|
}
|
|
226
259
|
export {
|
|
@@ -3,4 +3,4 @@ import type { AppShellProp } from "../../props/components/layout.prop.js";
|
|
|
3
3
|
export type { AppShellProp, AppShellProp as AppShellProps, } from "../../props/components/layout.prop.js";
|
|
4
4
|
/** Same rail boundary as shell-layout.css; SSR starts in docked mode. */
|
|
5
5
|
export declare function useAppShellNavigationMode(): "drawer" | "docked";
|
|
6
|
-
export declare function AppShell({ sidebar, topbar, topbarLeft, topbarRight, logo, breadcrumb, footer, children, sidebarCollapsed, responsiveNavigation, topbarSpan, navRail, navRailLabel, mobileNav, mobileNavLabel, mobileNavOpen, onMobileNavOpenChange, }: AppShellProp): React.JSX.Element;
|
|
6
|
+
export declare function AppShell({ sidebar, topbar, topbarLeft, topbarRight, logo, breadcrumb, footer, children, sidebarCollapsed, responsiveNavigation, topbarSpan, navRail, navRailPosition, navRailEnd, navRailLabel, mobileNav, mobileNavLabel, mobileNavOpen, onMobileNavOpenChange, }: AppShellProp): React.JSX.Element;
|