@eifi1/ui-kit 0.14.1 → 0.15.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 (156) hide show
  1. package/README.md +4 -3
  2. package/dist/components/alert-banner.js +5 -2
  3. package/dist/components/alert-banner.js.map +1 -1
  4. package/dist/components/amount-input.d.ts +9 -1
  5. package/dist/components/amount-input.js +10 -4
  6. package/dist/components/amount-input.js.map +1 -1
  7. package/dist/components/autocomplete.js +9 -2
  8. package/dist/components/autocomplete.js.map +1 -1
  9. package/dist/components/bulk-action-bar.js +6 -3
  10. package/dist/components/bulk-action-bar.js.map +1 -1
  11. package/dist/components/button-group.d.ts +1 -1
  12. package/dist/components/calculator.d.ts +1 -1
  13. package/dist/components/calendar-heatmap.js +5 -5
  14. package/dist/components/calendar-heatmap.js.map +1 -1
  15. package/dist/components/copy-button.d.ts +1 -1
  16. package/dist/components/data-table-cells.d.ts +1 -1
  17. package/dist/components/data-table-filter-popover.d.ts +1 -1
  18. package/dist/components/data-table-filter-popover.js +3 -3
  19. package/dist/components/data-table-filter-popover.js.map +1 -1
  20. package/dist/components/data-table-filters.d.ts +1 -1
  21. package/dist/components/data-table.d.ts +1 -1
  22. package/dist/components/data-table.js +12 -4
  23. package/dist/components/data-table.js.map +1 -1
  24. package/dist/components/error-boundary.js +2 -1
  25. package/dist/components/error-boundary.js.map +1 -1
  26. package/dist/components/field.js +4 -1
  27. package/dist/components/field.js.map +1 -1
  28. package/dist/components/file-button.d.ts +1 -1
  29. package/dist/components/file-dropzone.d.ts +1 -1
  30. package/dist/components/form-actions.d.ts +1 -1
  31. package/dist/components/image-grid.d.ts +8 -1
  32. package/dist/components/image-grid.js +16 -3
  33. package/dist/components/image-grid.js.map +1 -1
  34. package/dist/components/measured-grid.js +2 -2
  35. package/dist/components/measured-grid.js.map +1 -1
  36. package/dist/components/money-field.d.ts +92 -0
  37. package/dist/components/money-field.js +40 -0
  38. package/dist/components/money-field.js.map +1 -0
  39. package/dist/components/multi-select.js +3 -0
  40. package/dist/components/multi-select.js.map +1 -1
  41. package/dist/components/number-field.d.ts +13 -2
  42. package/dist/components/number-field.js +4 -0
  43. package/dist/components/number-field.js.map +1 -1
  44. package/dist/components/number-input.d.ts +5 -2
  45. package/dist/components/number-input.js +11 -3
  46. package/dist/components/number-input.js.map +1 -1
  47. package/dist/components/numpad-sheet.d.ts +1 -1
  48. package/dist/components/page-header.js +29 -3
  49. package/dist/components/page-header.js.map +1 -1
  50. package/dist/components/series-chart.js +37 -8
  51. package/dist/components/series-chart.js.map +1 -1
  52. package/dist/components/settings-fields.d.ts +1 -1
  53. package/dist/components/stat-tile.js +3 -3
  54. package/dist/components/stat-tile.js.map +1 -1
  55. package/dist/components/text-link.d.ts +1 -1
  56. package/dist/components/text-link.js +2 -1
  57. package/dist/components/text-link.js.map +1 -1
  58. package/dist/components/time-input.d.ts +1 -1
  59. package/dist/components/treemap.d.ts +3 -2
  60. package/dist/components/treemap.js +14 -3
  61. package/dist/components/treemap.js.map +1 -1
  62. package/dist/components/ui.d.ts +1 -1
  63. package/dist/components/ui.js +44 -10
  64. package/dist/components/ui.js.map +1 -1
  65. package/dist/components/use-table-state.d.ts +1 -1
  66. package/dist/{data-table-Drun8Fk9.d.ts → data-table-CfVXtCeG.d.ts} +4 -3
  67. package/dist/data-table.d.ts +1 -1
  68. package/dist/feedback/feedback-dialog.d.ts +10 -1
  69. package/dist/feedback/feedback-dialog.js +13 -3
  70. package/dist/feedback/feedback-dialog.js.map +1 -1
  71. package/dist/feedback/feedback-thread.js +31 -12
  72. package/dist/feedback/feedback-thread.js.map +1 -1
  73. package/dist/hooks/use-file-drop.d.ts +1 -1
  74. package/dist/i18n/defaults.d.ts +1 -1
  75. package/dist/i18n/kit-labels.d.ts +1 -1
  76. package/dist/i18n/locales/de-CH-informal.d.ts +1 -1
  77. package/dist/i18n/locales/de-CH.d.ts +1 -1
  78. package/dist/i18n/locales/de-informal.d.ts +1 -1
  79. package/dist/i18n/locales/de.d.ts +1 -1
  80. package/dist/i18n/locales/de.js +1 -0
  81. package/dist/i18n/locales/de.js.map +1 -1
  82. package/dist/i18n/locales/es.d.ts +1 -1
  83. package/dist/i18n/locales/es.js +1 -0
  84. package/dist/i18n/locales/es.js.map +1 -1
  85. package/dist/i18n/locales/fr.d.ts +1 -1
  86. package/dist/i18n/locales/fr.js +1 -0
  87. package/dist/i18n/locales/fr.js.map +1 -1
  88. package/dist/i18n/locales/hu.d.ts +1 -1
  89. package/dist/i18n/locales/hu.js +1 -0
  90. package/dist/i18n/locales/hu.js.map +1 -1
  91. package/dist/i18n/locales/it.d.ts +1 -1
  92. package/dist/i18n/locales/it.js +1 -0
  93. package/dist/i18n/locales/it.js.map +1 -1
  94. package/dist/i18n/locales/zh.d.ts +1 -1
  95. package/dist/i18n/locales/zh.js +1 -0
  96. package/dist/i18n/locales/zh.js.map +1 -1
  97. package/dist/index.d.ts +5 -4
  98. package/dist/index.js +1 -0
  99. package/dist/index.js.map +1 -1
  100. package/dist/{kit-labels-Mz8zZHIF.d.ts → kit-labels-BHfRBbHs.d.ts} +5 -1
  101. package/dist/lib/document-navigation.d.ts +15 -0
  102. package/dist/lib/document-navigation.js +13 -0
  103. package/dist/lib/document-navigation.js.map +1 -0
  104. package/dist/lib/strip-fade.d.ts +31 -0
  105. package/dist/lib/strip-fade.js +54 -0
  106. package/dist/lib/strip-fade.js.map +1 -0
  107. package/dist/rhf/fields.d.ts +1 -1
  108. package/dist/rhf/form.d.ts +1 -1
  109. package/dist/rhf/form.js +1 -1
  110. package/dist/rhf/form.js.map +1 -1
  111. package/dist/rhf.d.ts +1 -1
  112. package/dist/shell/app-shell.d.ts +11 -2
  113. package/dist/shell/app-shell.js +20 -4
  114. package/dist/shell/app-shell.js.map +1 -1
  115. package/dist/shell/top-bar-brand.d.ts +1 -1
  116. package/dist/shell.d.ts +1 -1
  117. package/dist/wizard/stepper-nav.d.ts +1 -1
  118. package/dist/wizard/stepper-nav.js +14 -2
  119. package/dist/wizard/stepper-nav.js.map +1 -1
  120. package/dist/wizard.d.ts +1 -1
  121. package/package.json +7 -4
  122. package/src/components/alert-banner.tsx +10 -2
  123. package/src/components/amount-input.tsx +18 -4
  124. package/src/components/autocomplete.tsx +10 -1
  125. package/src/components/bulk-action-bar.tsx +12 -3
  126. package/src/components/calendar-heatmap.tsx +10 -5
  127. package/src/components/data-table-filter-popover.tsx +6 -3
  128. package/src/components/data-table.tsx +21 -7
  129. package/src/components/error-boundary.tsx +2 -1
  130. package/src/components/field.tsx +4 -1
  131. package/src/components/image-grid.tsx +30 -2
  132. package/src/components/measured-grid.tsx +3 -2
  133. package/src/components/money-field.tsx +75 -0
  134. package/src/components/multi-select.tsx +3 -0
  135. package/src/components/number-field.tsx +14 -0
  136. package/src/components/number-input.tsx +23 -4
  137. package/src/components/page-header.tsx +38 -3
  138. package/src/components/series-chart.tsx +56 -8
  139. package/src/components/stat-tile.tsx +8 -3
  140. package/src/components/text-link.tsx +2 -1
  141. package/src/components/treemap.tsx +30 -5
  142. package/src/components/ui.tsx +91 -11
  143. package/src/feedback/feedback-dialog.tsx +20 -2
  144. package/src/feedback/feedback-thread.tsx +36 -13
  145. package/src/i18n/locales/de.ts +1 -0
  146. package/src/i18n/locales/es.ts +1 -0
  147. package/src/i18n/locales/fr.ts +1 -0
  148. package/src/i18n/locales/hu.ts +1 -0
  149. package/src/i18n/locales/it.ts +1 -0
  150. package/src/i18n/locales/zh.ts +1 -0
  151. package/src/index.ts +1 -0
  152. package/src/lib/document-navigation.ts +17 -0
  153. package/src/lib/strip-fade.ts +82 -0
  154. package/src/rhf/form.tsx +3 -1
  155. package/src/shell/app-shell.tsx +34 -7
  156. package/src/wizard/stepper-nav.tsx +23 -2
@@ -1,10 +1,11 @@
1
- import { createContext, useCallback, useContext, useEffect, useId, useRef, useState } from "react";
1
+ import { createContext, useCallback, useContext, useEffect, useId, useLayoutEffect, useRef, useState } from "react";
2
2
  import type { ComponentPropsWithoutRef, ReactNode } from "react";
3
3
  import { createPortal } from "react-dom";
4
4
  import { Link, NavLink, matchPath, useLocation } from "react-router";
5
5
  import { ChevronRight, PanelLeftClose, PanelLeftOpen } from "lucide-react";
6
6
  import type { LucideIcon } from "lucide-react";
7
7
  import { cn } from "../lib/cn";
8
+ import { scrollIntoStrip, useStripFade } from "../lib/strip-fade";
8
9
  import { dirOf, type Direction } from "../lib/direction";
9
10
  import { readStored, writeStored } from "../lib/safe-storage";
10
11
  import { Tooltip } from "../components/tooltip";
@@ -140,6 +141,15 @@ export interface AppShellProps extends ComponentPropsWithoutRef<"div"> {
140
141
  * bottom bar — the phone's counterpart of the sidebar's second level. Default true;
141
142
  * `false` keeps the single bar, where a group entry only links to its own `to`. */
142
143
  mobileSubNav?: boolean;
144
+ /**
145
+ * How the phone sub-nav lays out a group with more pages than fit on one row.
146
+ * `"wrap"` (default): every page in view, on as many rows as it takes — the bar
147
+ * grows. `"scroll"`: one row that scrolls sideways, faded at a cut edge, with the
148
+ * current page scrolled into view. A long group took four rows (~130px) of a 390px
149
+ * screen above the bottom bar (showcase audit); scrolling gives that back at the
150
+ * price of pages hidden past the edge, so it is the app's call, per shell.
151
+ */
152
+ mobileSubNavLayout?: "wrap" | "scroll";
143
153
  /**
144
154
  * Lay the shell out inside its PARENT'S box instead of the viewport: `h-full` rather
145
155
  * than `h-dvh`, its own scroll container at every width, a bottom bar pinned to the
@@ -255,6 +265,7 @@ export function AppShell({
255
265
  expandLabel,
256
266
  subNav = "flyout",
257
267
  mobileSubNav = true,
268
+ mobileSubNavLayout = "wrap",
258
269
  toggleGroupLabel,
259
270
  embedded: embeddedProp,
260
271
  className,
@@ -433,7 +444,7 @@ export function AppShell({
433
444
  ref={navRef}
434
445
  className="md:hidden fixed bottom-0 inset-x-0 z-30 border-t border-[var(--border)] bg-[var(--bg-surface)]"
435
446
  >
436
- {mobileSubNav && <MobileSubNav nav={nav} />}
447
+ {mobileSubNav && <MobileSubNav nav={nav} layout={mobileSubNavLayout} />}
437
448
  <nav
438
449
  data-tour="nav"
439
450
  className="grid"
@@ -586,8 +597,17 @@ function MobileNavItem({ item }: { item: AppShellNavItem }) {
586
597
  * It slides in over 200ms (fade only under reduced motion) and wraps onto more rows
587
598
  * rather than scrolling, so every page of the group is in view at once.
588
599
  */
589
- function MobileSubNav({ nav }: { nav: AppShellNavItem[] }) {
600
+ function MobileSubNav({ nav, layout }: { nav: AppShellNavItem[]; layout: "wrap" | "scroll" }) {
590
601
  const { pathname } = useLocation();
602
+ const scroll = layout === "scroll";
603
+ const listRef = useRef<HTMLUListElement>(null);
604
+ const fade = useStripFade(listRef);
605
+ // The current page into view — the row only, never the page.
606
+ useLayoutEffect(() => {
607
+ const list = listRef.current;
608
+ const current = list?.querySelector<HTMLElement>('[aria-current="page"]');
609
+ if (scroll && list && current) scrollIntoStrip(list, current);
610
+ }, [scroll, pathname]);
591
611
  const group = nav.find(
592
612
  (item) =>
593
613
  !!item.items?.length &&
@@ -604,10 +624,17 @@ function MobileSubNav({ nav }: { nav: AppShellNavItem[] }) {
604
624
  className="animate-subnav border-b border-[var(--border)]"
605
625
  >
606
626
  <ul
607
- // Wraps onto as many rows as the group needs rather than scrolling sideways: a
608
- // sideways row hides pages past the edge, and every page of the group in view
609
- // is the point of the row. The bar grows with it — `--app-nav-h` measures it.
610
- className="flex flex-wrap gap-1.5 px-3 py-2"
627
+ ref={listRef}
628
+ // `wrap` (default) takes as many rows as the group needs: a sideways row hides
629
+ // pages past the edge, and every page of the group in view is the point of the
630
+ // row. The bar grows with it — `--app-nav-h` measures it. `scroll` is the app's
631
+ // opt-in trade: one row, the cut edge faded (see mobileSubNavLayout).
632
+ className={cn(
633
+ "flex gap-1.5 px-3 py-2",
634
+ scroll ? "overflow-x-auto overscroll-x-contain [scrollbar-width:none]" : "flex-wrap",
635
+ )}
636
+ data-overflow={scroll ? fade.overflow : undefined}
637
+ style={scroll && fade.mask ? { maskImage: fade.mask, WebkitMaskImage: fade.mask } : undefined}
611
638
  >
612
639
  {group.items!.map((sub) => (
613
640
  <li key={sub.to} className="shrink-0">
@@ -1,4 +1,4 @@
1
- import { useId, useMemo } from "react";
1
+ import { useId, useLayoutEffect, useMemo, useRef, useState } from "react";
2
2
  import type { ReactElement, ReactNode } from "react";
3
3
  import { Check } from "lucide-react";
4
4
  import { cn } from "../lib/cn";
@@ -88,6 +88,25 @@ export function StepperNav<TData extends Record<string, unknown>>({
88
88
  const l = useKitLabels("wizard", DEFAULT_WIZARD_LABELS, labels);
89
89
  const cancelTitleId = useId();
90
90
 
91
+ // The step area never shrinks below the tallest step shown so far, so the button
92
+ // bar does not jump up and down as Next and Back move between a long step and a
93
+ // short one. This replaces a fixed `min-h-[300px]` (carried over from Kastlan,
94
+ // whose steps are all long forms), which did the same for steps under 300px but
95
+ // left a short wizard — two fields a step — with a ~200px hole above its buttons.
96
+ // Measured rather than guessed: the floor is whatever the app's own steps need.
97
+ const contentRef = useRef<HTMLDivElement>(null);
98
+ const [contentFloor, setContentFloor] = useState(0);
99
+ useLayoutEffect(() => {
100
+ const el = contentRef.current;
101
+ if (!el || typeof ResizeObserver === "undefined") return;
102
+ const observer = new ResizeObserver(() => {
103
+ const h = el.offsetHeight;
104
+ setContentFloor((floor) => (h > floor ? h : floor));
105
+ });
106
+ observer.observe(el);
107
+ return () => observer.disconnect();
108
+ }, []);
109
+
91
110
  const contextValue = useMemo(
92
111
  () => ({
93
112
  registerStepValidate: wizard.registerStepValidate,
@@ -235,7 +254,9 @@ export function StepperNav<TData extends Record<string, unknown>>({
235
254
 
236
255
  {/* Step content */}
237
256
  <WizardContextProvider value={contextValue}>
238
- <div className="min-h-[300px]">{children}</div>
257
+ <div style={contentFloor > 0 ? { minHeight: contentFloor } : undefined}>
258
+ <div ref={contentRef}>{children}</div>
259
+ </div>
239
260
  </WizardContextProvider>
240
261
 
241
262
  {/* Submit error */}