hlmnhkl-ui 0.35.1 → 0.35.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.
package/README.md CHANGED
@@ -9,6 +9,10 @@ React components, measured down to the part you never see: the 44px tap area, th
9
9
 
10
10
  **[Docs](https://ui.hlmnhkl.my)** · [Installation](https://ui.hlmnhkl.my/installation) · [Components](https://ui.hlmnhkl.my/button) · [What's new](https://ui.hlmnhkl.my/changelog)
11
11
 
12
+ <img alt="Four hlmnhkl/ui controls in use: a Dial turned to a new oven temperature, a RulerScrubber dragged and landing on a mark, a SwipeDeck card thrown right and the next thrown left, and a SplitFlap board flipping to new times." src="https://raw.githubusercontent.com/hilmanhaikal/hlmnhkl-ui/main/.github/assets/signature.gif" width="600">
13
+
14
+ Controls that feel like real ones: Dial, RulerScrubber, SwipeDeck, SplitFlap and more. Plus the everyday parts every app needs: buttons, inputs, sheets, tables, menus and 60 more.
15
+
12
16
  ## Install
13
17
 
14
18
  From your app's folder, set it up once, then copy the components you need:
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "hlmnhkl-ui",
3
- "version": "0.35.1",
3
+ "version": "0.35.2",
4
4
  "description": "React components in black, white and grey with one blue accent. Copy them into your app with npx hlmnhkl-ui add <name>.",
5
5
  "license": "MIT",
6
6
  "homepage": "https://ui.hlmnhkl.my",
@@ -147,8 +147,16 @@
147
147
  margin-inline: auto;
148
148
  }
149
149
 
150
+ /* Registered so the fill can ease back after a throw instead of snapping off in one frame. */
151
+ @property --fill {
152
+ syntax: '<number>';
153
+ inherits: true;
154
+ initial-value: 0;
155
+ }
156
+
150
157
  .choice {
151
158
  --fill: 0;
159
+ transition: --fill var(--hl-motion-base) var(--hl-ease-out);
152
160
  position: relative;
153
161
  display: grid;
154
162
  min-block-size: var(--hl-control-h-lg);
@@ -172,6 +180,10 @@
172
180
  white-space: nowrap;
173
181
  }
174
182
 
183
+ .root:has(.deck[data-dragging]) .choice {
184
+ transition: none;
185
+ }
186
+
175
187
  /* The fill pours in from the button's inner edge toward the side the card goes, and the word under it turns to its ink. */
176
188
  .fill {
177
189
  position: absolute;
@@ -1,6 +1,7 @@
1
1
  'use client'
2
2
 
3
3
  import { useEffect, useLayoutEffect, useRef, useState, type ComponentPropsWithRef, type KeyboardEvent, type PointerEvent, type ReactNode } from 'react'
4
+ import { flushSync } from 'react-dom'
4
5
  import { cx } from '../../internal/cx'
5
6
  import { clamp, magnetTo, pull, speedTracker, springTo } from '../../internal/feel'
6
7
  import { UndoIcon } from '../../internal/icons'
@@ -133,8 +134,10 @@ export function SwipeDeck<T>({
133
134
 
134
135
  const finish = (side: Side) => {
135
136
  stop.current = () => {}
137
+ // The next card must be in place before the top card's transform resets, or the thrown card
138
+ // shows in the middle for a frame.
139
+ flushSync(() => commit(side))
136
140
  paint(0)
137
- commit(side)
138
141
  }
139
142
 
140
143
  const fly = (side: Side, velocity: number) => {