@structured-id/ui-core 4.7.0 → 4.7.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.
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "@structured-id/ui-core",
3
- "version": "4.7.0",
3
+ "version": "4.7.1",
4
4
  "type": "module",
5
5
  "publishConfig": {
6
6
  "access": "public",
@@ -234,6 +234,29 @@ describe("SidPasswordCeremony", () => {
234
234
  expect(w.emitted("settled")).toEqual([["refused"]]);
235
235
  });
236
236
 
237
+ // With reduced motion the line still shows how far the operation went and
238
+ // that it is running: settled positions are solid, open ones are marked
239
+ // (they dissolve slowly instead of churning), so a running operation is
240
+ // never a frozen row of dots.
241
+ it("shows progress and activity under reduced motion", async () => {
242
+ vi.stubGlobal(
243
+ "matchMedia",
244
+ (query: string) =>
245
+ ({ matches: query.includes("reduce") }) as MediaQueryList,
246
+ );
247
+ const w = mountCeremony({ length: 10 });
248
+ await merged();
249
+ const settled = () =>
250
+ rows(w)[0].findAll(".sid-ceremony__glyph--set").length;
251
+ const open = () => rows(w)[0].findAll(".sid-ceremony__glyph--open").length;
252
+ expect(settled()).toBe(0);
253
+ expect(open()).toBe(10);
254
+ await w.setProps({ progress: at("prove", 0.5, "Building the proof") });
255
+ await vi.advanceTimersByTimeAsync(80);
256
+ expect(settled()).toBe(5);
257
+ expect(open()).toBe(5);
258
+ });
259
+
237
260
  // With reduced motion nothing churns and every step lands at once.
238
261
  it("does not animate under reduced motion", async () => {
239
262
  // jsdom has no matchMedia: the browser's answer is given here.
@@ -41,7 +41,11 @@
41
41
  v-for="(glyph, i) in glyphs"
42
42
  :key="i"
43
43
  class="sid-ceremony__glyph"
44
- :class="{ 'sid-ceremony__glyph--set': glyph === DOT }"
44
+ :class="
45
+ i < settledUpTo
46
+ ? 'sid-ceremony__glyph--set'
47
+ : 'sid-ceremony__glyph--open'
48
+ "
45
49
  >{{ glyph }}</span
46
50
  >
47
51
  </div>
@@ -150,6 +154,12 @@ const stageHeight = computed(
150
154
  );
151
155
  const count = computed(() => Math.max(1, Math.min(props.length, MAX_GLYPHS)));
152
156
  const glyphs = ref<string[]>(Array.from({ length: count.value }, () => DOT));
157
+ /**
158
+ * How many positions, from the left, the operation has settled. Kept apart
159
+ * from what the glyphs show: under reduced motion every position is a dot,
160
+ * and only this tells a settled one from an open one.
161
+ */
162
+ const settledUpTo = ref(0);
153
163
 
154
164
  const phase = ref<Phase>("split");
155
165
  const checked = ref(false);
@@ -249,12 +259,12 @@ const label = computed(() => {
249
259
  let ticks = 0;
250
260
  function tick() {
251
261
  pace();
252
- const settledUpTo = Math.floor(fraction.value * count.value);
262
+ settledUpTo.value = Math.floor(fraction.value * count.value);
253
263
  // The open digits change every fourth frame (about six times a second);
254
264
  // the line itself follows the pace every frame.
255
265
  const churning = !still && ticks++ % 4 === 0;
256
266
  glyphs.value = glyphs.value.map((glyph, i) => {
257
- if (i < settledUpTo) return DOT;
267
+ if (i < settledUpTo.value) return DOT;
258
268
  if (!churning) return still ? DOT : glyph;
259
269
  // A calm churn: about a third of the open digits change at a time.
260
270
  if (glyph !== DOT && Math.random() > 0.35) return glyph;
@@ -277,6 +287,7 @@ function stopChurn() {
277
287
  function close() {
278
288
  stopChurn();
279
289
  fraction.value = 1;
290
+ settledUpTo.value = count.value;
280
291
  glyphs.value = glyphs.value.map(() => DOT);
281
292
  phase.value = "orb";
282
293
  after(TIMING.orb, () => {
@@ -378,6 +389,20 @@ onBeforeUnmount(() => {
378
389
  opacity: 1;
379
390
  transform: scale(0.6);
380
391
  }
392
+ /* Under reduced motion the open positions dissolve slowly in place instead
393
+ of churning: no movement, but a running operation never looks frozen. */
394
+ .sid-ceremony--still .sid-ceremony__glyph--open {
395
+ transform: scale(0.6);
396
+ animation: sid-ceremony-dissolve 1.6s ease-in-out infinite alternate;
397
+ }
398
+ @keyframes sid-ceremony-dissolve {
399
+ from {
400
+ opacity: 0.15;
401
+ }
402
+ to {
403
+ opacity: 0.55;
404
+ }
405
+ }
381
406
  .sid-ceremony__orb {
382
407
  position: absolute;
383
408
  top: 50%;