@hogoshi/ui 0.1.5 → 0.1.6

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "@hogoshi/ui",
3
- "version": "0.1.5",
3
+ "version": "0.1.6",
4
4
  "type": "module",
5
5
  "repository": {
6
6
  "type": "git",
@@ -38,7 +38,7 @@
38
38
  },
39
39
  "dependencies": {
40
40
  "@base-ui/react": "^1.8.0",
41
- "@hogoshi/tokens": "^0.1.1",
41
+ "@hogoshi/tokens": "^0.1.2",
42
42
  "@hugeicons-pro/core-duotone-rounded": "^4.2.2",
43
43
  "@hugeicons-pro/core-solid-rounded": "^4.2.2",
44
44
  "@hugeicons-pro/core-stroke-rounded": "^4.2.2",
@@ -21,7 +21,7 @@ export function TopBar({ contained = false, children, className }: { contained?:
21
21
  const root = document.querySelector("[data-scroll-root]");
22
22
  const read = () => {
23
23
  const top = root instanceof HTMLElement ? root.scrollTop : window.scrollY;
24
- setCompact(top > 24);
24
+ setCompact((current) => (current ? top > 8 : top > 24));
25
25
  };
26
26
  read();
27
27
  const target: EventTarget = root instanceof HTMLElement ? root : window;
@@ -30,13 +30,13 @@ export function TopBar({ contained = false, children, className }: { contained?:
30
30
  }, []);
31
31
 
32
32
  return (
33
- <header className={cn("pointer-events-none inset-x-0 top-0 z-[var(--z-sticky)] flex justify-center", contained ? "absolute" : "fixed", className)}>
33
+ <header className={cn("pointer-events-none inset-x-0 top-0 z-[var(--z-sticky)]", contained ? "absolute" : "fixed", className)}>
34
34
  <div
35
35
  className={cn(
36
- "pointer-events-auto flex items-center transition-[width,height,margin,border-radius,background-color,border-color,box-shadow] duration-500 ease-[var(--motion-ease)] motion-reduce:transition-none",
36
+ "pointer-events-auto relative mx-auto flex h-12 items-center border transition-[width,translate,border-radius,background-color,border-color,box-shadow] duration-[calc(var(--motion-duration)*4)] ease-[var(--motion-ease)]",
37
37
  compact
38
- ? "border-border bg-bg-elevated mt-[calc(var(--safe-top)+0.75rem)] h-12 w-[min(40rem,calc(100%-1.5rem))] rounded-full border px-2 shadow-[var(--shadow-md)]"
39
- : "mt-[calc(var(--safe-top)+0.5rem)] h-14 w-full border border-transparent bg-transparent px-3",
38
+ ? "border-border bg-bg-elevated w-[min(40rem,calc(100%-max(0.75rem,var(--safe-left))-max(0.75rem,var(--safe-right))))] translate-y-[calc(var(--safe-top)+0.75rem)] rounded-full px-2 shadow-[var(--shadow-md)]"
39
+ : "before:pointer-events-auto w-full translate-y-[var(--safe-top)] border-transparent bg-transparent pl-[max(0.75rem,var(--safe-left))] pr-[max(0.75rem,var(--safe-right))] before:absolute before:inset-x-0 before:bottom-full before:h-[var(--safe-top)] before:content-['']",
40
40
  )}
41
41
  >
42
42
  <Navbar className="relative h-full w-full bg-transparent px-1 shadow-none backdrop-blur-none">{children}</Navbar>
@@ -154,7 +154,7 @@ export function BottomBar({ className, children, ...props }: ComponentProps<"nav
154
154
  return (
155
155
  <nav
156
156
  className={cn(
157
- "bg-bg-elevated/70 border-border fixed right-[max(0.75rem,var(--safe-right))] bottom-2 left-[max(0.75rem,var(--safe-left))] z-[var(--z-sticky)] rounded-[var(--radius-lg)] border p-1 shadow-[var(--shadow-md)] backdrop-blur-xl md:hidden",
157
+ "bg-bg-elevated/70 border-border fixed right-[max(0.75rem,var(--safe-right))] bottom-[max(0.5rem,var(--safe-bottom))] left-[max(0.75rem,var(--safe-left))] z-[var(--z-sticky)] rounded-[var(--radius-lg)] border p-1 shadow-[var(--shadow-md)] backdrop-blur-xl md:hidden",
158
158
  className,
159
159
  )}
160
160
  {...props}
@@ -33,8 +33,7 @@ function markScrolling(element: Element) {
33
33
 
34
34
  function motionAllowed() {
35
35
  const motion = document.documentElement.getAttribute("data-motion");
36
- if (motion === "off" || motion === "reduced") return false;
37
- return !window.matchMedia("(prefers-reduced-motion: reduce)").matches;
36
+ return motion !== "off" && motion !== "reduced";
38
37
  }
39
38
 
40
39
  function stop(element: Element) {
@@ -38,6 +38,41 @@ function freeze(media: HTMLVideoElement | HTMLCanvasElement, copy: Element) {
38
38
  copy.replaceWith(canvas);
39
39
  }
40
40
 
41
+ function lockScroll() {
42
+ const root = document.querySelector("[data-scroll-root]");
43
+ if (root instanceof HTMLElement) {
44
+ const top = root.scrollTop;
45
+ const left = root.scrollLeft;
46
+ return () => {
47
+ root.scrollTop = top;
48
+ root.scrollLeft = left;
49
+ };
50
+ }
51
+ const top = window.scrollY;
52
+ const left = window.scrollX;
53
+ const body = document.body;
54
+ const prev = {
55
+ position: body.style.position,
56
+ top: body.style.top,
57
+ left: body.style.left,
58
+ right: body.style.right,
59
+ width: body.style.width,
60
+ };
61
+ body.style.position = "fixed";
62
+ body.style.top = `-${top}px`;
63
+ body.style.left = "0";
64
+ body.style.right = "0";
65
+ body.style.width = "100%";
66
+ return () => {
67
+ body.style.position = prev.position;
68
+ body.style.top = prev.top;
69
+ body.style.left = prev.left;
70
+ body.style.right = prev.right;
71
+ body.style.width = prev.width;
72
+ window.scrollTo(left, top);
73
+ };
74
+ }
75
+
41
76
  function holdPage() {
42
77
  const root = document.documentElement;
43
78
  root.setAttribute("data-theme-switching", "");
@@ -160,9 +195,7 @@ export function ThemeToggle({
160
195
  if (switching) return;
161
196
  const root = document.documentElement;
162
197
  const next = root.getAttribute("data-mode") === "dark" ? "light" : "dark";
163
- const reduce =
164
- window.matchMedia("(prefers-reduced-motion: reduce)").matches || root.getAttribute("data-motion") === "off";
165
- if (reduce) {
198
+ if (root.getAttribute("data-motion") === "off") {
166
199
  swap(next);
167
200
  return;
168
201
  }
@@ -172,8 +205,10 @@ export function ThemeToggle({
172
205
  const current = next === "dark" ? "light" : "dark";
173
206
  const inward = next === "dark";
174
207
  const layer = snapshot(inward ? current : next);
208
+ const unlock = lockScroll();
175
209
  const finish = () => {
176
210
  layer.remove();
211
+ unlock();
177
212
  requestAnimationFrame(() => {
178
213
  requestAnimationFrame(() => {
179
214
  release();
package/src/styles.css CHANGED
@@ -61,6 +61,8 @@ body {
61
61
  color: var(--fg);
62
62
  font-family: var(--font-sans);
63
63
  font-size: var(--text-base);
64
+ min-height: 100%;
65
+ min-height: 100dvh;
64
66
  -webkit-font-smoothing: antialiased;
65
67
  text-rendering: optimizeLegibility;
66
68
  }
@@ -328,11 +330,6 @@ nav,
328
330
  to { opacity: 1; transform: scale(1); }
329
331
  }
330
332
 
331
- html[data-theme-switching],
332
- html[data-theme-switching] body {
333
- overflow: hidden !important;
334
- }
335
-
336
333
  html[data-theme-switching] body {
337
334
  pointer-events: none !important;
338
335
  }
@@ -432,12 +429,3 @@ button.hogoshi-grab:disabled {
432
429
  z-index: 0;
433
430
  }
434
431
 
435
- @media (prefers-reduced-motion: reduce) {
436
- *,
437
- *::before,
438
- *::after {
439
- animation-duration: 1ms !important;
440
- animation-iteration-count: 1 !important;
441
- transition-duration: 1ms !important;
442
- }
443
- }