@adecore/ui 0.46.1 → 0.46.2

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.
@@ -62,7 +62,7 @@ function NavTab(t0) {
62
62
  return t3;
63
63
  }
64
64
  function SettingsNav(t0) {
65
- const $ = _c(13);
65
+ const $ = _c(15);
66
66
  const {
67
67
  groups,
68
68
  footer,
@@ -71,64 +71,97 @@ function SettingsNav(t0) {
71
71
  const {
72
72
  t
73
73
  } = useTranslation("ui");
74
+ const list = useRef(null);
74
75
  let t1;
75
- if ($[0] !== t) {
76
- t1 = t("settings.sections");
77
- $[0] = t;
78
- $[1] = t1;
79
- } else {
80
- t1 = $[1];
81
- }
82
76
  let t2;
83
- if ($[2] !== groups) {
84
- t2 = groups.map(_temp2);
85
- $[2] = groups;
86
- $[3] = t2;
77
+ if ($[0] === Symbol.for("react.memo_cache_sentinel")) {
78
+ t1 = () => {
79
+ const element = list.current;
80
+ if (!element) {
81
+ return;
82
+ }
83
+ const mark = () => {
84
+ element.toggleAttribute("data-fade-start", element.scrollTop > 0);
85
+ element.toggleAttribute("data-fade-end", Math.ceil(element.scrollTop + element.clientHeight) < element.scrollHeight);
86
+ };
87
+ mark();
88
+ const observer = new ResizeObserver(mark);
89
+ observer.observe(element);
90
+ element.addEventListener("scroll", mark, {
91
+ passive: true
92
+ });
93
+ return () => {
94
+ observer.disconnect();
95
+ element.removeEventListener("scroll", mark);
96
+ };
97
+ };
98
+ t2 = [];
99
+ $[0] = t1;
100
+ $[1] = t2;
87
101
  } else {
88
- t2 = $[3];
102
+ t1 = $[0];
103
+ t2 = $[1];
89
104
  }
105
+ useEffect(t1, t2);
90
106
  let t3;
91
- if ($[4] !== t2) {
92
- t3 = /*#__PURE__*/_jsx("div", {
93
- className: "flex min-h-0 flex-col gap-3.5 overflow-y-auto",
94
- children: t2
95
- });
96
- $[4] = t2;
97
- $[5] = t3;
107
+ if ($[2] !== t) {
108
+ t3 = t("settings.sections");
109
+ $[2] = t;
110
+ $[3] = t3;
98
111
  } else {
99
- t3 = $[5];
112
+ t3 = $[3];
100
113
  }
101
114
  let t4;
102
- if ($[6] !== account || $[7] !== footer) {
103
- t4 = (footer?.length || account) && /*#__PURE__*/_jsxs("div", {
115
+ if ($[4] !== groups) {
116
+ t4 = groups.map(_temp2);
117
+ $[4] = groups;
118
+ $[5] = t4;
119
+ } else {
120
+ t4 = $[5];
121
+ }
122
+ let t5;
123
+ if ($[6] !== t4) {
124
+ t5 = /*#__PURE__*/_jsx("div", {
125
+ ref: list,
126
+ className: "scroll-fade-y flex min-h-0 flex-col gap-3.5 overflow-y-auto",
127
+ children: t4
128
+ });
129
+ $[6] = t4;
130
+ $[7] = t5;
131
+ } else {
132
+ t5 = $[7];
133
+ }
134
+ let t6;
135
+ if ($[8] !== account || $[9] !== footer) {
136
+ t6 = (footer?.length || account) && /*#__PURE__*/_jsxs("div", {
104
137
  className: "mt-auto flex flex-col gap-3 pt-3.5",
105
138
  children: [footer?.map(_temp3), account && /*#__PURE__*/_jsx("div", {
106
139
  className: "-mx-3 -mb-1 border-t border-border px-3 pt-3",
107
140
  children: account.tab
108
141
  })]
109
142
  });
110
- $[6] = account;
111
- $[7] = footer;
112
- $[8] = t4;
143
+ $[8] = account;
144
+ $[9] = footer;
145
+ $[10] = t6;
113
146
  } else {
114
- t4 = $[8];
147
+ t6 = $[10];
115
148
  }
116
- let t5;
117
- if ($[9] !== t1 || $[10] !== t3 || $[11] !== t4) {
118
- t5 = /*#__PURE__*/_jsxs(Tabs.List, {
119
- "aria-label": t1,
149
+ let t7;
150
+ if ($[11] !== t3 || $[12] !== t5 || $[13] !== t6) {
151
+ t7 = /*#__PURE__*/_jsxs(Tabs.List, {
152
+ "aria-label": t3,
120
153
  activateOnFocus: true,
121
154
  className: "flex min-h-0 grow flex-col",
122
- children: [t3, t4]
155
+ children: [t5, t6]
123
156
  });
124
- $[9] = t1;
125
- $[10] = t3;
126
- $[11] = t4;
157
+ $[11] = t3;
127
158
  $[12] = t5;
159
+ $[13] = t6;
160
+ $[14] = t7;
128
161
  } else {
129
- t5 = $[12];
162
+ t7 = $[14];
130
163
  }
131
- return t5;
164
+ return t7;
132
165
  }
133
166
  function _temp3(section_0) {
134
167
  return /*#__PURE__*/_jsx(NavTab, {
@@ -483,7 +516,7 @@ export function SettingsDialog(t0) {
483
516
  }
484
517
  let t14;
485
518
  if ($[27] !== className) {
486
- t14 = clsx("flex h-[760px] w-[1200px]", className);
519
+ t14 = clsx("flex h-[min(840px,calc(100dvh-64px))] w-[1200px]", className);
487
520
  $[27] = className;
488
521
  $[28] = t14;
489
522
  } else {
package/dist/theme.css CHANGED
@@ -592,6 +592,14 @@
592
592
  mask-image: linear-gradient(to bottom, transparent, #000 var(--fade-start));
593
593
  }
594
594
  .scroll-fade-top[data-fade-start] { --fade-start: 24px; }
595
+ /* A column that scrolls with something fixed above and below it fades at either end that still hides a row. */
596
+ .scroll-fade-y {
597
+ --fade-start: 0px;
598
+ --fade-end: 0px;
599
+ mask-image: linear-gradient(to bottom, transparent, #000 var(--fade-start), #000 calc(100% - var(--fade-end)), transparent);
600
+ }
601
+ .scroll-fade-y[data-fade-start] { --fade-start: 24px; }
602
+ .scroll-fade-y[data-fade-end] { --fade-end: 24px; }
595
603
 
596
604
  /* A toast's countdown ring; `TimerRing` sets duration and delay from the toast's own timer. */
597
605
  .toast-timer-arc { animation: toast-timer linear forwards; }
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "@adecore/ui",
3
- "version": "0.46.1",
3
+ "version": "0.46.2",
4
4
  "description": "React components, a theme, formatters and a settings dialog for desktop-grade apps on React 19, Base UI and Tailwind 4.",
5
5
  "license": "FSL-1.1-MIT",
6
6
  "author": "Bas Milius",
@@ -97,10 +97,35 @@ function NavTab({ section }: { section: SettingsSectionEntry }) {
97
97
 
98
98
  function SettingsNav({ groups, footer, account }: Pick<SettingsDialogProps, 'groups' | 'footer' | 'account'>) {
99
99
  const { t } = useTranslation('ui');
100
+ const list = useRef<HTMLDivElement>(null);
101
+
102
+ // A list cut off by the footer fades at the edge that hides a section, so the cut never reads as the end.
103
+ useEffect(() => {
104
+ const element = list.current;
105
+
106
+ if (!element) {
107
+ return;
108
+ }
109
+
110
+ const mark = (): void => {
111
+ element.toggleAttribute('data-fade-start', element.scrollTop > 0);
112
+ element.toggleAttribute('data-fade-end', Math.ceil(element.scrollTop + element.clientHeight) < element.scrollHeight);
113
+ };
114
+
115
+ mark();
116
+ const observer = new ResizeObserver(mark);
117
+ observer.observe(element);
118
+ element.addEventListener('scroll', mark, { passive: true });
119
+
120
+ return () => {
121
+ observer.disconnect();
122
+ element.removeEventListener('scroll', mark);
123
+ };
124
+ }, []);
100
125
 
101
126
  return (
102
127
  <Tabs.List aria-label={t('settings.sections')} activateOnFocus className="flex min-h-0 grow flex-col">
103
- <div className="flex min-h-0 flex-col gap-3.5 overflow-y-auto">
128
+ <div ref={list} className="scroll-fade-y flex min-h-0 flex-col gap-3.5 overflow-y-auto">
104
129
  {groups.map((group) => (
105
130
  <div key={group.sections[0]!.id} className="flex flex-col gap-0.5">
106
131
  {group.label !== null && <span className="px-2.5 pt-2.5 pb-1 text-xs font-medium text-text-faint">{group.label}</span>}
@@ -272,8 +297,9 @@ export function SettingsDialog({
272
297
  }}
273
298
  >
274
299
  {/* The width steps down with the viewport: a narrower navigation on a tablet, and a menu of
275
- sections instead of the column where even that leaves the panes too little room. */}
276
- <DialogPopup ref={ref} className={clsx('flex h-[760px] w-[1200px]', className)}>
300
+ sections instead of the column where even that leaves the panes too little room. The
301
+ height keeps the whole navigation in view where the screen allows it. */}
302
+ <DialogPopup ref={ref} className={clsx('flex h-[min(840px,calc(100dvh-64px))] w-[1200px]', className)}>
277
303
  <Tabs.Root
278
304
  value={meta.id}
279
305
  onValueChange={(value) => onNavigate({ section: value as string })}
package/src/theme.css CHANGED
@@ -592,6 +592,14 @@
592
592
  mask-image: linear-gradient(to bottom, transparent, #000 var(--fade-start));
593
593
  }
594
594
  .scroll-fade-top[data-fade-start] { --fade-start: 24px; }
595
+ /* A column that scrolls with something fixed above and below it fades at either end that still hides a row. */
596
+ .scroll-fade-y {
597
+ --fade-start: 0px;
598
+ --fade-end: 0px;
599
+ mask-image: linear-gradient(to bottom, transparent, #000 var(--fade-start), #000 calc(100% - var(--fade-end)), transparent);
600
+ }
601
+ .scroll-fade-y[data-fade-start] { --fade-start: 24px; }
602
+ .scroll-fade-y[data-fade-end] { --fade-end: 24px; }
595
603
 
596
604
  /* A toast's countdown ring; `TimerRing` sets duration and delay from the toast's own timer. */
597
605
  .toast-timer-arc { animation: toast-timer linear forwards; }