@nizivo/react 0.1.0 → 0.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.
Files changed (238) hide show
  1. package/THIRD_PARTY_NOTICES +12 -5
  2. package/dist/_engines/react-aria/dialog.client.js +16 -24
  3. package/dist/_engines/react-aria/drawer.client.js +8 -0
  4. package/dist/_engines/react-aria/file-upload.client.js +50 -0
  5. package/dist/_engines/react-aria/menu.client.js +17 -13
  6. package/dist/_engines/react-aria/open-state.client.js +53 -0
  7. package/dist/_engines/react-aria/outside-press.client.js +61 -0
  8. package/dist/_engines/react-aria/overlay.client.js +6 -1
  9. package/dist/_engines/react-aria/popover.client.js +148 -0
  10. package/dist/_engines/react-aria/popup.client.js +31 -5
  11. package/dist/_engines/react-aria/select.client.js +22 -12
  12. package/dist/_engines/react-aria/toast.client.js +38 -0
  13. package/dist/_engines/react-aria/tooltip.client.js +11 -11
  14. package/dist/_internal/data-status.d.ts +3 -0
  15. package/dist/_internal/data-status.js +13 -0
  16. package/dist/_internal/glyphs.js +54 -1
  17. package/dist/_internal/modal.client.js +54 -0
  18. package/dist/_internal/nested-focus.js +33 -0
  19. package/dist/alert/alert-dismiss.client.d.ts +1 -1
  20. package/dist/alert/alert-dismiss.client.js +3 -1
  21. package/dist/app-shell/app-shell.d.ts +24 -0
  22. package/dist/app-shell/app-shell.js +56 -0
  23. package/dist/app-shell/index.d.ts +2 -0
  24. package/dist/app-shell/index.js +1 -0
  25. package/dist/avatar/avatar.d.ts +96 -0
  26. package/dist/avatar/avatar.js +94 -0
  27. package/dist/avatar/index.d.ts +2 -0
  28. package/dist/avatar/index.js +1 -0
  29. package/dist/banner/banner-dismiss.client.d.ts +32 -0
  30. package/dist/banner/banner-dismiss.client.js +38 -0
  31. package/dist/banner/banner.d.ts +34 -0
  32. package/dist/banner/banner.js +47 -0
  33. package/dist/banner/index.d.ts +3 -0
  34. package/dist/banner/index.js +3 -0
  35. package/dist/breadcrumb/breadcrumb.d.ts +46 -0
  36. package/dist/breadcrumb/breadcrumb.js +46 -0
  37. package/dist/breadcrumb/breadcrumb.parts.d.ts +6 -0
  38. package/dist/breadcrumb/breadcrumb.parts.js +9 -0
  39. package/dist/breadcrumb/index.d.ts +3 -0
  40. package/dist/breadcrumb/index.js +3 -0
  41. package/dist/button/button.d.ts +3 -2
  42. package/dist/card/card.d.ts +9 -2
  43. package/dist/chip-group/chip-group.client.d.ts +88 -0
  44. package/dist/chip-group/chip-group.client.js +157 -0
  45. package/dist/chip-group/index.d.ts +2 -0
  46. package/dist/chip-group/index.js +1 -0
  47. package/dist/choice-card/choice-card.client.d.ts +66 -0
  48. package/dist/choice-card/choice-card.client.js +138 -0
  49. package/dist/choice-card/index.d.ts +2 -0
  50. package/dist/choice-card/index.js +1 -0
  51. package/dist/config/config.client.d.ts +16 -1
  52. package/dist/config/config.client.js +18 -3
  53. package/dist/config/index.d.ts +2 -2
  54. package/dist/contracts/index.d.ts +1 -1
  55. package/dist/css/app-shell.css +2 -0
  56. package/dist/css/avatar.css +2 -0
  57. package/dist/css/banner.css +2 -0
  58. package/dist/css/base.css +1 -1
  59. package/dist/css/breadcrumb.css +2 -0
  60. package/dist/css/card.css +1 -1
  61. package/dist/css/chip-group.css +2 -0
  62. package/dist/css/choice-card.css +2 -0
  63. package/dist/css/delta.css +1 -1
  64. package/dist/css/drawer.css +2 -0
  65. package/dist/css/file-upload.css +2 -0
  66. package/dist/css/form.css +2 -0
  67. package/dist/css/heading.css +1 -1
  68. package/dist/css/kpi-tile.css +2 -0
  69. package/dist/css/metric.css +2 -0
  70. package/dist/css/mobile-tab-bar.css +2 -0
  71. package/dist/css/mobile-top-bar.css +2 -0
  72. package/dist/css/motion.css +2 -0
  73. package/dist/css/nav-item.css +2 -0
  74. package/dist/css/number-value.css +2 -0
  75. package/dist/css/page-header.css +2 -0
  76. package/dist/css/pagination.css +2 -0
  77. package/dist/css/password-input.css +2 -0
  78. package/dist/css/popover.css +2 -0
  79. package/dist/css/ranked-list.css +2 -0
  80. package/dist/css/search-field.css +2 -0
  81. package/dist/css/sidebar.css +2 -0
  82. package/dist/css/split.css +2 -0
  83. package/dist/css/sticky-bar.css +2 -0
  84. package/dist/css/table-selection.css +2 -0
  85. package/dist/css/table.css +2 -0
  86. package/dist/css/text.css +1 -1
  87. package/dist/css/toast.css +2 -0
  88. package/dist/css/top-bar.css +2 -0
  89. package/dist/css/trend-card.css +2 -0
  90. package/dist/dialog/dialog.client.d.ts +1 -1
  91. package/dist/dialog/dialog.client.js +15 -37
  92. package/dist/drawer/drawer.client.d.ts +25 -0
  93. package/dist/drawer/drawer.client.js +154 -0
  94. package/dist/drawer/drawer.contract.d.ts +98 -0
  95. package/dist/drawer/drawer.parts.d.ts +6 -0
  96. package/dist/drawer/drawer.parts.js +16 -0
  97. package/dist/drawer/index.d.ts +5 -0
  98. package/dist/drawer/index.js +3 -0
  99. package/dist/field/field-scope.client.js +9 -2
  100. package/dist/file-upload/file-upload.client.d.ts +9 -0
  101. package/dist/file-upload/file-upload.client.js +406 -0
  102. package/dist/file-upload/file-upload.contract.d.ts +112 -0
  103. package/dist/file-upload/index.d.ts +3 -0
  104. package/dist/file-upload/index.js +1 -0
  105. package/dist/file-upload/seam.d.ts +1 -0
  106. package/dist/form/form.client.d.ts +38 -0
  107. package/dist/form/form.client.js +127 -0
  108. package/dist/form/form.d.ts +36 -0
  109. package/dist/form/form.js +29 -0
  110. package/dist/form/index.d.ts +4 -0
  111. package/dist/form/index.js +4 -0
  112. package/dist/form/submit-button.client.d.ts +20 -0
  113. package/dist/form/submit-button.client.js +19 -0
  114. package/dist/heading/heading.d.ts +4 -1
  115. package/dist/i18n/format-label.d.ts +24 -0
  116. package/dist/i18n/format-label.js +19 -0
  117. package/dist/i18n/index.d.ts +2 -0
  118. package/dist/i18n/index.js +1 -0
  119. package/dist/icon-button/icon-button.client.js +1 -1
  120. package/dist/icon-button/icon-button.js +1 -1
  121. package/dist/index.d.ts +84 -5
  122. package/dist/index.js +49 -4
  123. package/dist/kpi-tile/index.d.ts +2 -0
  124. package/dist/kpi-tile/index.js +1 -0
  125. package/dist/kpi-tile/kpi-tile.d.ts +30 -0
  126. package/dist/kpi-tile/kpi-tile.js +48 -0
  127. package/dist/locales/en-US.d.ts +77 -0
  128. package/dist/locales/en-US.js +83 -0
  129. package/dist/menu/menu.contract.d.ts +1 -1
  130. package/dist/metric/index.d.ts +2 -0
  131. package/dist/metric/index.js +1 -0
  132. package/dist/metric/metric.d.ts +72 -0
  133. package/dist/metric/metric.js +116 -0
  134. package/dist/mobile-tab-bar/index.d.ts +4 -0
  135. package/dist/mobile-tab-bar/index.js +4 -0
  136. package/dist/mobile-tab-bar/mobile-tab-bar-inset.client.js +38 -0
  137. package/dist/mobile-tab-bar/mobile-tab-bar-more.client.d.ts +26 -0
  138. package/dist/mobile-tab-bar/mobile-tab-bar-more.client.js +60 -0
  139. package/dist/mobile-tab-bar/mobile-tab-bar.d.ts +39 -0
  140. package/dist/mobile-tab-bar/mobile-tab-bar.js +54 -0
  141. package/dist/mobile-tab-bar/mobile-tab-bar.parts.d.ts +6 -0
  142. package/dist/mobile-tab-bar/mobile-tab-bar.parts.js +9 -0
  143. package/dist/mobile-top-bar/index.d.ts +2 -0
  144. package/dist/mobile-top-bar/index.js +1 -0
  145. package/dist/mobile-top-bar/mobile-top-bar.d.ts +17 -0
  146. package/dist/mobile-top-bar/mobile-top-bar.js +31 -0
  147. package/dist/motion/count-up.client.d.ts +39 -0
  148. package/dist/motion/count-up.client.js +109 -0
  149. package/dist/motion/index.d.ts +2 -0
  150. package/dist/motion/index.js +1 -0
  151. package/dist/nav-item/index.d.ts +2 -0
  152. package/dist/nav-item/index.js +1 -0
  153. package/dist/nav-item/nav-item.d.ts +35 -0
  154. package/dist/nav-item/nav-item.js +50 -0
  155. package/dist/number-value/index.d.ts +2 -0
  156. package/dist/number-value/index.js +1 -0
  157. package/dist/number-value/number-value.d.ts +25 -0
  158. package/dist/number-value/number-value.js +26 -0
  159. package/dist/page-header/index.d.ts +2 -0
  160. package/dist/page-header/index.js +1 -0
  161. package/dist/page-header/page-header.d.ts +19 -0
  162. package/dist/page-header/page-header.js +39 -0
  163. package/dist/pagination/index.d.ts +2 -0
  164. package/dist/pagination/index.js +1 -0
  165. package/dist/pagination/pagination.d.ts +74 -0
  166. package/dist/pagination/pagination.js +136 -0
  167. package/dist/password-input/index.d.ts +2 -0
  168. package/dist/password-input/index.js +1 -0
  169. package/dist/password-input/password-input.client.d.ts +52 -0
  170. package/dist/password-input/password-input.client.js +106 -0
  171. package/dist/popover/index.d.ts +5 -0
  172. package/dist/popover/index.js +3 -0
  173. package/dist/popover/popover.client.d.ts +20 -0
  174. package/dist/popover/popover.client.js +113 -0
  175. package/dist/popover/popover.contract.d.ts +88 -0
  176. package/dist/popover/popover.parts.d.ts +6 -0
  177. package/dist/popover/popover.parts.js +13 -0
  178. package/dist/ranked-list/index.d.ts +3 -0
  179. package/dist/ranked-list/index.js +3 -0
  180. package/dist/ranked-list/ranked-list.d.ts +85 -0
  181. package/dist/ranked-list/ranked-list.js +153 -0
  182. package/dist/ranked-list/ranked-list.parts.d.ts +6 -0
  183. package/dist/ranked-list/ranked-list.parts.js +10 -0
  184. package/dist/search-field/index.d.ts +2 -0
  185. package/dist/search-field/index.js +1 -0
  186. package/dist/search-field/search-field.client.d.ts +55 -0
  187. package/dist/search-field/search-field.client.js +136 -0
  188. package/dist/select/select.contract.d.ts +1 -1
  189. package/dist/sidebar/index.d.ts +4 -0
  190. package/dist/sidebar/index.js +4 -0
  191. package/dist/sidebar/sidebar-item.client.d.ts +10 -0
  192. package/dist/sidebar/sidebar-item.client.js +55 -0
  193. package/dist/sidebar/sidebar.d.ts +45 -0
  194. package/dist/sidebar/sidebar.js +62 -0
  195. package/dist/sidebar/sidebar.parts.d.ts +6 -0
  196. package/dist/sidebar/sidebar.parts.js +11 -0
  197. package/dist/split/index.d.ts +3 -0
  198. package/dist/split/index.js +3 -0
  199. package/dist/split/split.d.ts +28 -0
  200. package/dist/split/split.js +33 -0
  201. package/dist/split/split.parts.d.ts +6 -0
  202. package/dist/split/split.parts.js +10 -0
  203. package/dist/sticky-bar/index.d.ts +2 -0
  204. package/dist/sticky-bar/index.js +1 -0
  205. package/dist/sticky-bar/sticky-bar.d.ts +16 -0
  206. package/dist/sticky-bar/sticky-bar.js +26 -0
  207. package/dist/styles.css +66 -7
  208. package/dist/table/index.d.ts +3 -0
  209. package/dist/table/index.js +3 -0
  210. package/dist/table/table.d.ts +101 -0
  211. package/dist/table/table.js +121 -0
  212. package/dist/table/table.parts.d.ts +6 -0
  213. package/dist/table/table.parts.js +18 -0
  214. package/dist/table-selection/index.d.ts +3 -0
  215. package/dist/table-selection/index.js +3 -0
  216. package/dist/table-selection/table-selection.client.d.ts +14 -0
  217. package/dist/table-selection/table-selection.client.js +84 -0
  218. package/dist/table-selection/table-selection.d.ts +34 -0
  219. package/dist/table-selection/table-selection.js +50 -0
  220. package/dist/text/text.d.ts +13 -2
  221. package/dist/toast/index.d.ts +4 -0
  222. package/dist/toast/index.js +3 -0
  223. package/dist/toast/seam.d.ts +2 -0
  224. package/dist/toast/store.d.ts +19 -0
  225. package/dist/toast/store.js +136 -0
  226. package/dist/toast/toast.contract.d.ts +56 -0
  227. package/dist/toast/toaster.client.d.ts +10 -0
  228. package/dist/toast/toaster.client.js +305 -0
  229. package/dist/tooltip/tooltip.contract.d.ts +1 -1
  230. package/dist/top-bar/index.d.ts +2 -0
  231. package/dist/top-bar/index.js +1 -0
  232. package/dist/top-bar/top-bar.d.ts +17 -0
  233. package/dist/top-bar/top-bar.js +35 -0
  234. package/dist/trend-card/index.d.ts +2 -0
  235. package/dist/trend-card/index.js +1 -0
  236. package/dist/trend-card/trend-card.d.ts +34 -0
  237. package/dist/trend-card/trend-card.js +74 -0
  238. package/package.json +167 -4
@@ -0,0 +1,30 @@
1
+ import { RenderProp } from "../contracts/render.js";
2
+ import { DataStatus } from "../_internal/data-status.js";
3
+ import { MetricDataProps } from "../metric/metric.js";
4
+ import { ComponentPropsWithRef, ReactElement, ReactNode } from "react";
5
+ //#region src/kpi-tile/kpi-tile.d.ts
6
+ /** Figma "Tone": Surface, or Tinted as `brand` or `accent` (Card's tones of the same names). */
7
+ export type KpiTileTone = "surface" | "brand" | "accent";
8
+ export interface KpiTileState {
9
+ /** The status as rendered: `'empty'` when a ready tile has no value. */
10
+ status: DataStatus;
11
+ pending: boolean;
12
+ tone: KpiTileTone;
13
+ }
14
+ export interface KpiTileProps extends MetricDataProps, Omit<ComponentPropsWithRef<"div">, "children"> {
15
+ /** The surface; group a row of related KPIs with one tint. @default 'surface' */
16
+ tone?: KpiTileTone;
17
+ /**
18
+ * A small chart beside the value, shown while ready, for example
19
+ * `<Sparkline data={series} label="Sales, last 7 days" />` from `@nizivo/charts`. Drawn at most
20
+ * 88 × 28 px (Figma).
21
+ */
22
+ chart?: ReactNode;
23
+ render?: RenderProp<KpiTileState>;
24
+ }
25
+ /**
26
+ * One number, its change and its shape. A `role="group"` named by the label (not a landmark). The
27
+ * Suspense fallback is the same tile with `status="loading"`: the box does not change (§16.5).
28
+ */
29
+ export declare function KpiTile({ label, value, format, locale, delta, comparison, chart, tone, status, pending, empty, error, labels, render, className, ...rest }: KpiTileProps): ReactElement;
30
+ //#endregion
@@ -0,0 +1,48 @@
1
+ import { cx } from "../_internal/cx.js";
2
+ import { renderElement } from "../contracts/render.js";
3
+ import { dataStatusAttrs } from "../_internal/data-status.js";
4
+ import { Metric, resolveStatus } from "../metric/metric.js";
5
+ import { useId } from "react";
6
+ import { jsx } from "react/jsx-runtime";
7
+ //#region src/kpi-tile/kpi-tile.tsx
8
+ /**
9
+ * One number, its change and its shape. A `role="group"` named by the label (not a landmark). The
10
+ * Suspense fallback is the same tile with `status="loading"`: the box does not change (§16.5).
11
+ */
12
+ function KpiTile({ label, value, format, locale, delta, comparison, chart, tone = "surface", status = "ready", pending = false, empty, error, labels, render, className, ...rest }) {
13
+ const labelId = useId();
14
+ const st = resolveStatus(status, value);
15
+ const busy = st === "ready" && pending;
16
+ return renderElement("div", render, {
17
+ status: st,
18
+ pending: busy,
19
+ tone
20
+ }, {
21
+ "data-slot": "kpi-tile",
22
+ "data-tone": tone,
23
+ "data-padding": "sm",
24
+ ...dataStatusAttrs(st, busy),
25
+ role: "group",
26
+ "aria-labelledby": labelId,
27
+ ...rest,
28
+ className: cx("nz-card", "nz-kpi-tile", className),
29
+ children: /* @__PURE__ */ jsx(Metric, {
30
+ labelId,
31
+ label,
32
+ value,
33
+ format,
34
+ locale,
35
+ delta,
36
+ comparison,
37
+ chart,
38
+ status,
39
+ pending,
40
+ empty,
41
+ error,
42
+ labels,
43
+ reserveChange: true
44
+ })
45
+ });
46
+ }
47
+ //#endregion
48
+ export { KpiTile };
@@ -0,0 +1,77 @@
1
+ import { AlertDismissLabels } from "../alert/alert-dismiss.client.js";
2
+ import "../alert/index.js";
3
+ import { AppShellLabels } from "../app-shell/app-shell.js";
4
+ import "../app-shell/index.js";
5
+ import { AvatarGroupLabels } from "../avatar/avatar.js";
6
+ import "../avatar/index.js";
7
+ import { BannerDismissLabels } from "../banner/banner-dismiss.client.js";
8
+ import "../banner/index.js";
9
+ import { BreadcrumbLabels } from "../breadcrumb/breadcrumb.js";
10
+ import "../breadcrumb/index.js";
11
+ import { ButtonLabels } from "../button/button.js";
12
+ import "../button/index.js";
13
+ import { ChipGroupLabels } from "../chip-group/chip-group.client.js";
14
+ import "../chip-group/index.js";
15
+ import { DialogLabels } from "../dialog/dialog.contract.js";
16
+ import "../dialog/index.js";
17
+ import { DrawerLabels } from "../drawer/drawer.contract.js";
18
+ import "../drawer/index.js";
19
+ import { FileUploadLabels } from "../file-upload/file-upload.contract.js";
20
+ import "../file-upload/index.js";
21
+ import { FormLabels } from "../form/form.client.js";
22
+ import "../form/index.js";
23
+ import { MetricLabels } from "../metric/metric.js";
24
+ import "../metric/index.js";
25
+ import { MobileTabBarLabels } from "../mobile-tab-bar/mobile-tab-bar.js";
26
+ import { MobileTabBarMoreLabels } from "../mobile-tab-bar/mobile-tab-bar-more.client.js";
27
+ import "../mobile-tab-bar/index.js";
28
+ import { PaginationLabels } from "../pagination/pagination.js";
29
+ import "../pagination/index.js";
30
+ import { PasswordInputLabels } from "../password-input/password-input.client.js";
31
+ import "../password-input/index.js";
32
+ import { PopoverLabels } from "../popover/popover.contract.js";
33
+ import "../popover/index.js";
34
+ import { RankedListLabels } from "../ranked-list/ranked-list.js";
35
+ import "../ranked-list/index.js";
36
+ import { SearchFieldLabels } from "../search-field/search-field.client.js";
37
+ import "../search-field/index.js";
38
+ import { SidebarLabels } from "../sidebar/sidebar.js";
39
+ import "../sidebar/index.js";
40
+ import { TableSelectionLabels } from "../table-selection/table-selection.js";
41
+ import "../table-selection/index.js";
42
+ import { ToasterLabels } from "../toast/toast.contract.js";
43
+ import "../toast/index.js";
44
+ //#region src/locales/en-US.d.ts
45
+ /**
46
+ * The en-US strings of every component that takes `labels`, keyed by component: pass
47
+ * `labels={enUS.pagination}` or a catalogue of the same shape for another locale
48
+ * (`const deDE: typeof enUS = { … }`). Count-bearing strings (`avatarGroup`) may be plural
49
+ * objects in other locales (`PluralLabel` from `@nizivo/react/i18n`).
50
+ */
51
+ export declare const enUS: {
52
+ alertDismiss: AlertDismissLabels;
53
+ appShell: AppShellLabels;
54
+ avatarGroup: AvatarGroupLabels;
55
+ bannerDismiss: BannerDismissLabels;
56
+ breadcrumb: BreadcrumbLabels;
57
+ button: ButtonLabels;
58
+ chipGroup: ChipGroupLabels;
59
+ dialog: Pick<DialogLabels, "close">;
60
+ drawer: Pick<DrawerLabels, "close">;
61
+ fileUpload: FileUploadLabels;
62
+ form: FormLabels;
63
+ kpiTile: MetricLabels;
64
+ metric: MetricLabels;
65
+ mobileTabBar: MobileTabBarLabels;
66
+ mobileTabBarMore: MobileTabBarMoreLabels;
67
+ pagination: PaginationLabels;
68
+ passwordInput: PasswordInputLabels;
69
+ popover: Pick<PopoverLabels, "close">;
70
+ rankedList: RankedListLabels;
71
+ searchField: SearchFieldLabels;
72
+ sidebar: SidebarLabels;
73
+ tableSelection: TableSelectionLabels;
74
+ toaster: ToasterLabels;
75
+ trendCard: MetricLabels;
76
+ };
77
+ //#endregion
@@ -0,0 +1,83 @@
1
+ //#region src/locales/en-US.ts
2
+ /**
3
+ * The en-US strings of every component that takes `labels`, keyed by component: pass
4
+ * `labels={enUS.pagination}` or a catalogue of the same shape for another locale
5
+ * (`const deDE: typeof enUS = { … }`). Count-bearing strings (`avatarGroup`) may be plural
6
+ * objects in other locales (`PluralLabel` from `@nizivo/react/i18n`).
7
+ */
8
+ const enUS = {
9
+ alertDismiss: { dismiss: "Dismiss" },
10
+ appShell: { skip: "Skip to content" },
11
+ avatarGroup: {
12
+ overflow: "+{count}",
13
+ more: "{count} more"
14
+ },
15
+ bannerDismiss: { dismiss: "Dismiss" },
16
+ breadcrumb: { nav: "Breadcrumb" },
17
+ button: { pending: "Loading…" },
18
+ chipGroup: { unavailable: "Unavailable" },
19
+ dialog: { close: "Close" },
20
+ drawer: { close: "Close" },
21
+ fileUpload: {
22
+ prompt: "Drop files here or {browse}",
23
+ browse: "browse",
24
+ release: "Release to add files",
25
+ summary: "{complete} of {total} uploaded",
26
+ wrongType: "{name} is not an accepted file type.",
27
+ tooLarge: "{name} is larger than {max}.",
28
+ tooMany: "{name} was not added: choose one file.",
29
+ list: "Chosen files",
30
+ remove: "Remove {name}",
31
+ retry: "Retry",
32
+ cancel: "Cancel",
33
+ uploading: "Uploading {name}",
34
+ complete: "Uploaded",
35
+ failed: "Upload failed"
36
+ },
37
+ form: { summaryTitle: "There is a problem" },
38
+ kpiTile: {
39
+ loading: "Loading {label}",
40
+ empty: "No data",
41
+ error: "Could not load {label}"
42
+ },
43
+ metric: {
44
+ loading: "Loading {label}",
45
+ empty: "No data",
46
+ error: "Could not load {label}"
47
+ },
48
+ mobileTabBar: { nav: "Primary" },
49
+ mobileTabBarMore: {
50
+ more: "More",
51
+ close: "Close"
52
+ },
53
+ pagination: {
54
+ nav: "Pagination",
55
+ previous: "Previous page",
56
+ next: "Next page",
57
+ page: "Page {page}"
58
+ },
59
+ passwordInput: { toggle: "Show password" },
60
+ popover: { close: "Close" },
61
+ rankedList: {
62
+ loading: "Loading {label}",
63
+ empty: "No data",
64
+ error: "Could not load {label}"
65
+ },
66
+ searchField: {
67
+ label: "Search",
68
+ clear: "Clear search"
69
+ },
70
+ sidebar: { nav: "Primary" },
71
+ tableSelection: { selectAll: "Select all rows" },
72
+ toaster: {
73
+ region: "Notifications (F8)",
74
+ dismiss: "Dismiss"
75
+ },
76
+ trendCard: {
77
+ loading: "Loading {label}",
78
+ empty: "No data",
79
+ error: "Could not load {label}"
80
+ }
81
+ };
82
+ //#endregion
83
+ export { enUS };
@@ -1,7 +1,7 @@
1
1
  import { RenderProp } from "../contracts/render.js";
2
2
  import { ChangeDetails, OpenReason } from "../contracts/details.js";
3
- import { Align, Side } from "../contracts/state.js";
4
3
  import "../_internal/engine-part.js";
4
+ import { Align, Side } from "../contracts/state.js";
5
5
  import { CSSProperties, ComponentPropsWithRef, HTMLAttributeAnchorTarget, HTMLAttributeReferrerPolicy, ReactElement, ReactNode } from "react";
6
6
  //#region src/menu/menu.contract.d.ts
7
7
  /** Logical side; the resolved physical side is `data-side` on the popup. */
@@ -0,0 +1,2 @@
1
+ import { Metric, MetricDataProps, MetricLabels, MetricProps, MetricSize, MetricState, metricLabels } from "./metric.js";
2
+ export { Metric, type MetricDataProps, type MetricLabels, type MetricProps, type MetricSize, type MetricState, metricLabels };
@@ -0,0 +1 @@
1
+ export { Metric, metricLabels } from "./metric.js";
@@ -0,0 +1,72 @@
1
+ import { RenderProp } from "../contracts/render.js";
2
+ import { DataStatus } from "../_internal/data-status.js";
3
+ import { ComponentPropsWithRef, ReactElement, ReactNode } from "react";
4
+ //#region src/metric/metric.d.ts
5
+ /** `default`: Numeric/KPI, the change on its own row (KPI Tile). `display`: Numeric/Display, the change beside the number (Revenue Card). */
6
+ export type MetricSize = "default" | "display";
7
+ /**
8
+ * Strings Metric renders (§16.4), all visually hidden or replaceable by a slot. `{label}` is replaced
9
+ * by the `label` prop.
10
+ */
11
+ export interface MetricLabels {
12
+ /** Static text while `status="loading"` (§16.5: `aria-busy` plus this, no live region). @default 'Loading {label}' */
13
+ loading: string;
14
+ /** Read after the "—" when there is no value and no `empty` slot. @default 'No data' */
15
+ empty: string;
16
+ /** The InlineError message when loading failed and there is no `error` slot. @default 'Could not load {label}' */
17
+ error: string;
18
+ }
19
+ /** English defaults of Metric's strings; KpiTile and TrendCard use them too. */
20
+ export declare const metricLabels: MetricLabels;
21
+ export interface MetricState {
22
+ /** The status as rendered: `'empty'` when a ready metric has no value. */
23
+ status: DataStatus;
24
+ pending: boolean;
25
+ size: MetricSize;
26
+ }
27
+ /** The value and status props Metric, KpiTile and TrendCard share. */
28
+ export interface MetricDataProps {
29
+ /** The name of the number, for example "Total sales". Also names the status texts. */
30
+ label: ReactNode;
31
+ /** The number. `null` or `undefined` (or `NaN`) with `status="ready"` renders the empty state. */
32
+ value?: number | null | undefined;
33
+ /** `Intl.NumberFormat` options for the value. @default {} */
34
+ format?: Intl.NumberFormatOptions | undefined;
35
+ /** BCP 47 tag for the value and a numeric `delta`. @default 'en-US' */
36
+ locale?: string | undefined;
37
+ /**
38
+ * The change. A number renders `<Delta value={delta} locale={locale} />` (a fraction: `0.124` is
39
+ * "+12.4%"); pass your own `<Delta … />` element for another format, a tone or an icon.
40
+ */
41
+ delta?: number | ReactElement | undefined;
42
+ /** Visible text after the delta, for example "vs last week". */
43
+ comparison?: ReactNode | undefined;
44
+ /** §16.5 lifecycle. @default 'ready' */
45
+ status?: DataStatus | undefined;
46
+ /** A refresh is in flight while the value shows: `data-pending` and `aria-busy`. */
47
+ pending?: boolean | undefined;
48
+ /** Replaces the "—" of the empty state. */
49
+ empty?: ReactNode | undefined;
50
+ /** Replaces the InlineError of the error state, for example one with a Retry `action`. */
51
+ error?: ReactNode | undefined;
52
+ labels?: Partial<MetricLabels> | undefined;
53
+ }
54
+ export interface MetricProps extends MetricDataProps, Omit<ComponentPropsWithRef<"div">, "children"> {
55
+ /** @default 'default' */
56
+ size?: MetricSize;
57
+ /**
58
+ * A small chart at the end of the value row, for example a Sparkline; shown while ready. Its box is
59
+ * at most the row's (KpiTile draws it at 88 × 28, Figma's tile).
60
+ */
61
+ chart?: ReactNode;
62
+ /** The id of the label element, for an enclosing group's `aria-labelledby` (KpiTile sets it). */
63
+ labelId?: string;
64
+ /**
65
+ * Keep the change row's height when there is no `delta` and no `comparison`, so the box is the same
66
+ * whatever a fallback passes (KpiTile and TrendCard set it: Figma's tile and card always have it).
67
+ */
68
+ reserveChange?: boolean;
69
+ render?: RenderProp<MetricState>;
70
+ }
71
+ export declare function Metric({ label, value, format, locale, delta, comparison, status, pending, empty, error, labels, size, chart, labelId, reserveChange, render, className, ...rest }: MetricProps): ReactElement;
72
+ //#endregion
@@ -0,0 +1,116 @@
1
+ import { cx } from "../_internal/cx.js";
2
+ import { renderElement } from "../contracts/render.js";
3
+ import { InlineError } from "../inline-error/inline-error.js";
4
+ import { Delta } from "../delta/delta.js";
5
+ import { dataStatusAttrs } from "../_internal/data-status.js";
6
+ import { NumberValue } from "../number-value/number-value.js";
7
+ import { Skeleton } from "../skeleton/skeleton.js";
8
+ import { Fragment, jsx, jsxs } from "react/jsx-runtime";
9
+ //#region src/metric/metric.tsx
10
+ /** English defaults of Metric's strings; KpiTile and TrendCard use them too. */
11
+ const metricLabels = {
12
+ loading: "Loading {label}",
13
+ empty: "No data",
14
+ error: "Could not load {label}"
15
+ };
16
+ /** `template` with its `{label}` replaced by the label node (which may be an element). */
17
+ function fillLabel(template, label) {
18
+ const at = template.indexOf("{label}");
19
+ if (at < 0) return template;
20
+ return /* @__PURE__ */ jsxs(Fragment, { children: [
21
+ template.slice(0, at),
22
+ label,
23
+ template.slice(at + 7)
24
+ ] });
25
+ }
26
+ /** The status Metric renders: a ready metric without a finite-or-infinite number is empty. */
27
+ function resolveStatus(status, value) {
28
+ return status === "ready" && (value == null || Number.isNaN(value)) ? "empty" : status;
29
+ }
30
+ function Metric({ label, value, format, locale = "en-US", delta, comparison, status = "ready", pending = false, empty, error, labels, size = "default", chart, labelId, reserveChange = false, render, className, ...rest }) {
31
+ const L = {
32
+ ...metricLabels,
33
+ ...labels
34
+ };
35
+ const st = resolveStatus(status, value);
36
+ const ready = st === "ready";
37
+ const busy = ready && pending;
38
+ let shown;
39
+ if (st === "loading") shown = /* @__PURE__ */ jsxs(Fragment, { children: [/* @__PURE__ */ jsx(Skeleton, {
40
+ shape: "block",
41
+ className: "nz-metric-value-skeleton"
42
+ }), /* @__PURE__ */ jsx("span", {
43
+ className: "nz-visually-hidden",
44
+ children: fillLabel(L.loading, label)
45
+ })] });
46
+ else if (st === "error") shown = error ?? /* @__PURE__ */ jsx(InlineError, { children: fillLabel(L.error, label) });
47
+ else if (st === "empty") shown = empty ?? /* @__PURE__ */ jsxs("span", {
48
+ className: "nz-metric-empty",
49
+ "data-slot": "metric-empty",
50
+ children: [/* @__PURE__ */ jsx("span", {
51
+ "aria-hidden": "true",
52
+ children: "—"
53
+ }), /* @__PURE__ */ jsx("span", {
54
+ className: "nz-visually-hidden",
55
+ children: fillLabel(L.empty, label)
56
+ })]
57
+ });
58
+ else shown = /* @__PURE__ */ jsx(NumberValue, {
59
+ className: "nz-metric-value",
60
+ value: value ?? 0,
61
+ format,
62
+ locale
63
+ });
64
+ const hasChange = delta !== void 0 || comparison != null;
65
+ let change;
66
+ if (hasChange || reserveChange) change = /* @__PURE__ */ jsx("div", {
67
+ className: "nz-metric-change",
68
+ "data-slot": "metric-change",
69
+ children: st === "loading" && hasChange ? /* @__PURE__ */ jsx(Skeleton, {
70
+ shape: "block",
71
+ className: "nz-metric-change-skeleton"
72
+ }) : ready && /* @__PURE__ */ jsxs(Fragment, { children: [typeof delta === "number" ? /* @__PURE__ */ jsx(Delta, {
73
+ value: delta,
74
+ locale
75
+ }) : delta, comparison != null && /* @__PURE__ */ jsx("span", {
76
+ className: "nz-metric-comparison",
77
+ "data-slot": "metric-comparison",
78
+ children: comparison
79
+ })] })
80
+ });
81
+ return renderElement("div", render, {
82
+ status: st,
83
+ pending: busy,
84
+ size
85
+ }, {
86
+ "data-slot": "metric",
87
+ "data-size": size,
88
+ ...dataStatusAttrs(st, busy),
89
+ ...rest,
90
+ className: cx("nz-metric", className),
91
+ children: /* @__PURE__ */ jsxs(Fragment, { children: [
92
+ /* @__PURE__ */ jsx("div", {
93
+ className: "nz-metric-label",
94
+ "data-slot": "metric-label",
95
+ id: labelId,
96
+ children: label
97
+ }),
98
+ /* @__PURE__ */ jsxs("div", {
99
+ className: "nz-metric-value-row",
100
+ "data-slot": "metric-value-row",
101
+ children: [
102
+ shown,
103
+ size === "display" && change,
104
+ chart != null && ready && /* @__PURE__ */ jsx("div", {
105
+ className: "nz-metric-chart",
106
+ "data-slot": "metric-chart",
107
+ children: chart
108
+ })
109
+ ]
110
+ }),
111
+ size === "default" && change
112
+ ] })
113
+ });
114
+ }
115
+ //#endregion
116
+ export { Metric, fillLabel, metricLabels, resolveStatus };
@@ -0,0 +1,4 @@
1
+ import { MobileTabBarItem, MobileTabBarItemProps, MobileTabBarItemState, MobileTabBarLabels, MobileTabBarRoot, MobileTabBarRootProps } from "./mobile-tab-bar.js";
2
+ import { MobileTabBarMore, MobileTabBarMoreLabels, MobileTabBarMoreProps } from "./mobile-tab-bar-more.client.js";
3
+ import { mobile_tab_bar_parts_d_exports } from "./mobile-tab-bar.parts.js";
4
+ export { mobile_tab_bar_parts_d_exports as MobileTabBar, MobileTabBarItem, type MobileTabBarItemProps, type MobileTabBarItemState, type MobileTabBarLabels, MobileTabBarMore, type MobileTabBarMoreLabels, type MobileTabBarMoreProps, MobileTabBarRoot, type MobileTabBarRootProps };
@@ -0,0 +1,4 @@
1
+ import { MobileTabBarItem, MobileTabBarRoot } from "./mobile-tab-bar.js";
2
+ import { MobileTabBarMore } from "./mobile-tab-bar-more.client.js";
3
+ import { mobile_tab_bar_parts_exports } from "./mobile-tab-bar.parts.js";
4
+ export { mobile_tab_bar_parts_exports as MobileTabBar, MobileTabBarItem, MobileTabBarMore, MobileTabBarRoot };
@@ -0,0 +1,38 @@
1
+ "use client";
2
+ import { useLayoutEffect, useRef } from "react";
3
+ import { jsx } from "react/jsx-runtime";
4
+ //#region src/mobile-tab-bar/mobile-tab-bar-inset.client.tsx
5
+ const INSET = "--nz-layout-bottom-inset";
6
+ const MARK = "data-nz-bottom-bar";
7
+ function MobileTabBarInset() {
8
+ const ref = useRef(null);
9
+ useLayoutEffect(() => {
10
+ const bar = ref.current?.parentElement;
11
+ if (bar == null || typeof ResizeObserver === "undefined") return void 0;
12
+ const root = document.documentElement;
13
+ const write = () => {
14
+ const height = bar.getBoundingClientRect().height;
15
+ if (height > 0) {
16
+ root.style.setProperty(INSET, `${height}px`);
17
+ root.setAttribute(MARK, "");
18
+ } else {
19
+ root.style.removeProperty(INSET);
20
+ root.removeAttribute(MARK);
21
+ }
22
+ };
23
+ write();
24
+ const observer = new ResizeObserver(write);
25
+ observer.observe(bar);
26
+ return () => {
27
+ observer.disconnect();
28
+ root.style.removeProperty(INSET);
29
+ root.removeAttribute(MARK);
30
+ };
31
+ }, []);
32
+ return /* @__PURE__ */ jsx("span", {
33
+ ref,
34
+ hidden: true
35
+ });
36
+ }
37
+ //#endregion
38
+ export { MobileTabBarInset };
@@ -0,0 +1,26 @@
1
+ import { DrawerTriggerProps } from "../drawer/drawer.contract.js";
2
+ import { ReactElement, ReactNode } from "react";
3
+ //#region src/mobile-tab-bar/mobile-tab-bar-more.client.d.ts
4
+ /** Strings this part renders (§16.4). */
5
+ export interface MobileTabBarMoreLabels {
6
+ /** The button's label in the bar, and the sheet's title. @default 'More' */
7
+ more: string;
8
+ /** The sheet's close button. @default 'Close' */
9
+ close: string;
10
+ }
11
+ export interface MobileTabBarMoreProps extends Omit<DrawerTriggerProps, "render" | "children"> {
12
+ /**
13
+ * The page being shown is one of the sheet's: draws the bar's filled indicator on More. It is a
14
+ * button, so nothing is announced; the sheet's link carries `aria-current`. @default false
15
+ */
16
+ current?: boolean;
17
+ /** The glyph in the bar. Defaults to the internal `ellipsis` (Lucide's). */
18
+ icon?: ReactNode;
19
+ /** The sheet's title, when it differs from the button's label. */
20
+ heading?: ReactNode;
21
+ labels?: Partial<MobileTabBarMoreLabels>;
22
+ /** The sheet's content: the other destinations, usually `NavItem`s. */
23
+ children: ReactNode;
24
+ }
25
+ export declare function MobileTabBarMore({ current, icon, heading, labels: labelsProp, className, children, ...rest }: MobileTabBarMoreProps): ReactElement;
26
+ //#endregion
@@ -0,0 +1,60 @@
1
+ "use client";
2
+ import { cx } from "../_internal/cx.js";
3
+ import { useLabels } from "../config/config.client.js";
4
+ import { EllipsisGlyph } from "../_internal/glyphs.js";
5
+ import { DrawerBody, DrawerClose, DrawerHeader, DrawerPopup, DrawerRoot, DrawerTitle, DrawerTrigger } from "../drawer/drawer.client.js";
6
+ import { useState } from "react";
7
+ import { jsx, jsxs } from "react/jsx-runtime";
8
+ //#region src/mobile-tab-bar/mobile-tab-bar-more.client.tsx
9
+ function MobileTabBarMore({ current = false, icon, heading, labels: labelsProp, className, children, ...rest }) {
10
+ const labels = useLabels("mobileTabBarMore", labelsProp);
11
+ const [open, setOpen] = useState(false);
12
+ const more = labels?.more ?? "More";
13
+ const closeOnLink = (event) => {
14
+ if (event.target instanceof Element && event.target.closest("a[href]") !== null) setOpen(false);
15
+ };
16
+ return /* @__PURE__ */ jsx("li", {
17
+ className: "nz-mobile-tab-bar-more",
18
+ "data-slot": "mobile-tab-bar-more",
19
+ children: /* @__PURE__ */ jsxs(DrawerRoot, {
20
+ open,
21
+ onOpenChange: setOpen,
22
+ children: [/* @__PURE__ */ jsx(DrawerTrigger, {
23
+ ...rest,
24
+ render: (props) => /* @__PURE__ */ jsxs("button", {
25
+ ...props,
26
+ type: "button",
27
+ "data-slot": "mobile-tab-bar-more-trigger",
28
+ "data-current": current ? "" : void 0,
29
+ className: cx("nz-mobile-tab-bar-more-trigger", typeof props["className"] === "string" ? props["className"] : void 0, className),
30
+ children: [/* @__PURE__ */ jsx("span", {
31
+ className: "nz-mobile-tab-bar-more-indicator",
32
+ "data-slot": "mobile-tab-bar-more-indicator",
33
+ children: /* @__PURE__ */ jsx("span", {
34
+ className: "nz-mobile-tab-bar-icon",
35
+ "aria-hidden": "true",
36
+ children: icon ?? /* @__PURE__ */ jsx(EllipsisGlyph, {})
37
+ })
38
+ }), /* @__PURE__ */ jsx("span", {
39
+ className: "nz-mobile-tab-bar-more-label",
40
+ "data-slot": "mobile-tab-bar-more-label",
41
+ children: more
42
+ })]
43
+ })
44
+ }), /* @__PURE__ */ jsxs(DrawerPopup, {
45
+ side: "bottom",
46
+ children: [
47
+ /* @__PURE__ */ jsx(DrawerHeader, { children: /* @__PURE__ */ jsx(DrawerTitle, { children: heading ?? more }) }),
48
+ /* @__PURE__ */ jsx(DrawerClose, { labels: { close: labels?.close ?? "Close" } }),
49
+ /* @__PURE__ */ jsx(DrawerBody, {
50
+ className: "nz-mobile-tab-bar-more-sheet",
51
+ onClick: closeOnLink,
52
+ children
53
+ })
54
+ ]
55
+ })]
56
+ })
57
+ });
58
+ }
59
+ //#endregion
60
+ export { MobileTabBarMore };
@@ -0,0 +1,39 @@
1
+ import { RenderProp } from "../contracts/render.js";
2
+ import { ComponentPropsWithRef, ReactElement, ReactNode } from "react";
3
+ //#region src/mobile-tab-bar/mobile-tab-bar.d.ts
4
+ /** Strings this part renders (§16.4). */
5
+ export interface MobileTabBarLabels {
6
+ /** The navigation landmark's name. @default 'Primary' */
7
+ nav: string;
8
+ }
9
+ export interface MobileTabBarItemState {
10
+ current: boolean;
11
+ }
12
+ export interface MobileTabBarRootProps extends ComponentPropsWithRef<"nav"> {
13
+ labels?: Partial<MobileTabBarLabels>;
14
+ /** The destinations: `MobileTabBar.Item`s, and `MobileTabBarMore` last. Five at most fit. */
15
+ children: ReactNode;
16
+ }
17
+ export interface MobileTabBarItemProps extends Omit<ComponentPropsWithRef<"a">, "children"> {
18
+ /** The page being shown: `aria-current="page"` and the filled indicator. @default false */
19
+ current?: boolean;
20
+ /** A decorative 20 px glyph in the indicator; it is `aria-hidden`. */
21
+ icon: ReactNode;
22
+ /**
23
+ * A count on the icon's corner, such as open orders. It is part of the link's text, so it is
24
+ * announced with the label: write it so it reads well there ("12 open").
25
+ */
26
+ count?: ReactNode;
27
+ /** The router's link, for example `render={<Link href="/orders" />}`. It must render an `<a>`. */
28
+ render?: RenderProp<MobileTabBarItemState>;
29
+ /** The label under the icon. */
30
+ children: ReactNode;
31
+ }
32
+ /** The `<nav>` and its list, with the bottom-inset island. */
33
+ export declare function MobileTabBarRoot({ labels, className, children, ...rest }: MobileTabBarRootProps): ReactElement;
34
+ /**
35
+ * One destination: a list item around a link, with its icon in Figma's indicator pill and its label
36
+ * under it. Props other than `icon`, `count` and `current` go to the link.
37
+ */
38
+ export declare function MobileTabBarItem({ current, icon, count, render, className, children, ...rest }: MobileTabBarItemProps): ReactElement;
39
+ //#endregion