@godxjp/ui 20.1.0 → 20.2.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 (54) hide show
  1. package/dist/app/app-provider.js +37 -21
  2. package/dist/app/index.d.ts +2 -0
  3. package/dist/app/index.js +2 -0
  4. package/dist/app/storage.d.ts +17 -0
  5. package/dist/app/storage.js +28 -0
  6. package/dist/components/data-display/popover.d.ts +7 -1
  7. package/dist/components/data-display/popover.js +4 -0
  8. package/dist/components/data-display/service-launcher-card.js +4 -2
  9. package/dist/components/data-display/table.d.ts +60 -0
  10. package/dist/components/data-display/table.js +8 -0
  11. package/dist/components/data-entry/calendar.d.ts +1 -1
  12. package/dist/components/data-entry/calendar.js +11 -2
  13. package/dist/components/feedback/dialog.js +3 -0
  14. package/dist/components/feedback/sheet.js +3 -0
  15. package/dist/components/feedback/tooltip.js +3 -0
  16. package/dist/components/general/button.d.ts +1 -0
  17. package/dist/components/general/button.js +2 -0
  18. package/dist/components/layout/app-launcher.d.ts +1 -1
  19. package/dist/components/layout/app-launcher.js +43 -10
  20. package/dist/components/layout/app-shell.d.ts +1 -1
  21. package/dist/components/layout/app-shell.js +14 -7
  22. package/dist/components/layout/auth-shell.d.ts +1 -1
  23. package/dist/components/layout/auth-shell.js +2 -0
  24. package/dist/components/layout/sidebar.js +2 -1
  25. package/dist/components/navigation/dropdown-menu.js +5 -0
  26. package/dist/components/ui/hover-card.js +3 -0
  27. package/dist/i18n/index.d.ts +1 -1
  28. package/dist/i18n/index.js +3 -1
  29. package/dist/i18n/messages/en.json +3 -1
  30. package/dist/i18n/messages/ja.json +3 -1
  31. package/dist/i18n/messages/vi.json +3 -1
  32. package/dist/i18n/translate.d.ts +19 -0
  33. package/dist/i18n/translate.js +24 -0
  34. package/dist/lib/overlay-portal.d.ts +18 -0
  35. package/dist/lib/overlay-portal.js +17 -0
  36. package/dist/props/components/app.prop.d.ts +13 -2
  37. package/dist/props/components/general.prop.d.ts +13 -0
  38. package/dist/props/components/layout.prop.d.ts +95 -5
  39. package/dist/styles/card-layout.css +10 -1
  40. package/dist/styles/chart-layout.css +2 -1
  41. package/dist/styles/control.css +5 -0
  42. package/dist/styles/data-display-layout.css +7 -1
  43. package/dist/styles/navigation-layout.css +3 -1
  44. package/dist/styles/shell-layout.css +465 -20
  45. package/dist/tokens/components/control.css +2 -1
  46. package/dist/tokens/components/shell.css +50 -3
  47. package/dist/tokens/foundation.css +2 -0
  48. package/docs/data-display/list-row.tsx +6 -6
  49. package/docs/layout/app-launcher.tsx +44 -0
  50. package/docs/layout/app-shell-arrangements.tsx +5 -5
  51. package/docs/showcase/settings-security-mfa.tsx +3 -3
  52. package/package.json +7 -4
  53. package/scripts/_agent-setup.mjs +57 -7
  54. package/scripts/visual-audit.mjs +45 -7
@@ -14,7 +14,13 @@ import {
14
14
  enableLiveRelativeFormatting,
15
15
  syncDatetimeContext
16
16
  } from "../lib/datetime/index.js";
17
- import { DEFAULT_STORAGE_KEY, readStoredPreferences, writeStoredPreferences } from "./storage.js";
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 = persist ? readStoredPreferences(storageKey) : {};
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
- persist,
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
- if (persist) writeStoredPreferences(storageKey, prefsRef.current);
207
+ commitPreferences();
192
208
  },
193
- [onLocaleChange, persist, storageKey]
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
- if (persist) writeStoredPreferences(storageKey, prefsRef.current);
216
+ commitPreferences();
201
217
  },
202
- [onTimezoneChange, persist, storageKey]
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
- if (persist) writeStoredPreferences(storageKey, prefsRef.current);
225
+ commitPreferences();
210
226
  },
211
- [onTimeFormatChange, persist, storageKey]
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
- if (persist) writeStoredPreferences(storageKey, prefsRef.current);
234
+ commitPreferences();
219
235
  },
220
- [onDateFormatChange, persist, storageKey]
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
- if (persist) writeStoredPreferences(storageKey, prefsRef.current);
243
+ commitPreferences();
228
244
  },
229
- [onThemeChange, persist, storageKey]
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
- if (persist) writeStoredPreferences(storageKey, prefsRef.current);
252
+ commitPreferences();
237
253
  },
238
- [onBrandChange, persist, storageKey]
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
- if (persist) writeStoredPreferences(storageKey, prefsRef.current);
261
+ commitPreferences();
246
262
  },
247
- [onDensityChange, persist, storageKey]
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
- if (persist) writeStoredPreferences(storageKey, prefsRef.current);
270
+ commitPreferences();
255
271
  },
256
- [onFontSizeChange, persist, storageKey]
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
- if (persist) writeStoredPreferences(storageKey, prefsRef.current);
279
+ commitPreferences();
264
280
  },
265
- [onScalingChange, persist, storageKey]
281
+ [onScalingChange, commitPreferences]
266
282
  );
267
283
  const requestHeaders = React.useMemo(
268
284
  () => buildRequestHeaders(locale, timezone, timeFormat, dateFormat),
@@ -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,
@@ -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 };
@@ -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__ */ jsx("span", { "data-slot": "service-launcher-icon", "aria-hidden": "true", children: /* @__PURE__ */ jsx(Icon, {}) }),
35
- /* @__PURE__ */ jsx(Heading, { "data-slot": "service-launcher-title", children: title }),
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
- labelNav: labels?.labelNav ?? (() => `${ariaLabel ?? "Calendar"} navigation`)
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 trigger = /* @__PURE__ */ jsx(
180
- TopbarItem,
181
- {
182
- className: cn("ui-app-launcher-trigger", className),
183
- "aria-label": labels.trigger,
184
- ...rest,
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(PopoverContent, { align: "end", className: "ui-app-launcher-popover", "aria-label": labels.title, children: panel })
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;