hazo_ui 3.2.1 → 3.4.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/CHANGE_LOG.md +78 -0
- package/README.md +70 -2
- package/SETUP_CHECKLIST.md +3 -2
- package/dist/index.cjs +192 -0
- package/dist/index.cjs.map +1 -1
- package/dist/index.d.cts +336 -173
- package/dist/index.d.ts +336 -173
- package/dist/index.js +185 -1
- package/dist/index.js.map +1 -1
- package/dist/test-harness/index.cjs +61 -24
- package/dist/test-harness/index.cjs.map +1 -1
- package/dist/test-harness/index.d.cts +38 -26
- package/dist/test-harness/index.d.ts +38 -26
- package/dist/test-harness/index.js +60 -23
- package/dist/test-harness/index.js.map +1 -1
- package/package.json +9 -3
package/CHANGE_LOG.md
CHANGED
|
@@ -5,6 +5,84 @@ All notable changes to this project will be documented in this file.
|
|
|
5
5
|
The format is based on [Keep a Changelog](https://keepachangelog.com/en/1.0.0/),
|
|
6
6
|
and this project adheres to [Semantic Versioning](https://semver.org/spec/v2.0.0.html).
|
|
7
7
|
|
|
8
|
+
## v3.4.1 — 2026-06-12
|
|
9
|
+
|
|
10
|
+
**Fix:** Webpack compatibility in test-harness format.ts + source sync.
|
|
11
|
+
|
|
12
|
+
- Changed `require("node:fs")` → `require("fs")` in `src/test-harness/scenarios/format.ts`. The `"node:"` prefix triggers webpack's `UnhandledSchemeError` at build time before the try/catch can degrade in the browser. The bare specifier allows webpack to stub it as an empty module on the client (resolve.fallback), and Next.js gracefully falls through the catch on the server. Both forms transpile to identical `__require("fs")` in dist.
|
|
13
|
+
- Added `"use client"` directive to `src/index.ts` (already applied by tsup post-processing in dist, now the source matches).
|
|
14
|
+
- Test-app: added `/device-hooks` nav entry for the new interactive demo.
|
|
15
|
+
|
|
16
|
+
## v3.4.0 — 2026-06-12
|
|
17
|
+
|
|
18
|
+
**New:** `use_wake_lock(active)` and `use_fullscreen()` — snake_case declarative hook variants (FR-001).
|
|
19
|
+
|
|
20
|
+
Adds two thin wrapper hooks for snake_case consumers (the gotimer family) that can't adopt
|
|
21
|
+
`useWakeLock` / `useFullscreen` verbatim because the existing hooks have different contracts.
|
|
22
|
+
Both hooks delegate to their camelCase counterparts for all DOM-API logic (visibility-reacquire,
|
|
23
|
+
unmount-release, SSR safety).
|
|
24
|
+
|
|
25
|
+
- **`use_wake_lock(active: boolean): void`** — declarative; the screen wake lock is held while
|
|
26
|
+
`active` is `true` and released when it becomes `false`. No imperative `request()`/`release()`
|
|
27
|
+
calls required.
|
|
28
|
+
- **`use_fullscreen<T>(): { is_fullscreen, toggle, ref }`** — self-binding; creates the ref
|
|
29
|
+
internally and returns it alongside `is_fullscreen: boolean` and `toggle: () => Promise<void>`.
|
|
30
|
+
The consumer attaches `ref` to the element to fullscreen.
|
|
31
|
+
|
|
32
|
+
```ts
|
|
33
|
+
import { use_wake_lock, use_fullscreen } from "hazo_ui";
|
|
34
|
+
|
|
35
|
+
// Declarative wake lock
|
|
36
|
+
use_wake_lock(timer.is_running);
|
|
37
|
+
|
|
38
|
+
// Self-binding fullscreen
|
|
39
|
+
const { is_fullscreen, toggle, ref } = use_fullscreen();
|
|
40
|
+
return <div ref={ref}><button onClick={toggle}>Fullscreen</button></div>;
|
|
41
|
+
```
|
|
42
|
+
|
|
43
|
+
**Note:** The base `useFullscreen` hook syncs on the native `fullscreenchange` event. gotimer's
|
|
44
|
+
local hook also had an Escape-key fallback for a browser-specific optimistic CSS state — this
|
|
45
|
+
edge case is not included in `use_fullscreen` to avoid changing base-hook behaviour. Escape still
|
|
46
|
+
exits real fullscreen via the `fullscreenchange` listener.
|
|
47
|
+
|
|
48
|
+
**Exports added:** `use_wake_lock`, `use_fullscreen`, `UseFullscreenRefResult`.
|
|
49
|
+
|
|
50
|
+
## v3.3.0 — 2026-06-11
|
|
51
|
+
|
|
52
|
+
**New:** Required `doc` field on `Case` + per-case documentation accordion in `AutoTestRunner`.
|
|
53
|
+
|
|
54
|
+
Every test case registered via `registerScenario` must now declare a `doc: CaseDoc` with four
|
|
55
|
+
required string fields: `description`, `inputs`, `expectedOutputs`, and `caveats`. The field is
|
|
56
|
+
enforced at the type level — a case without `doc` fails `tsc`. All 20 existing scenario files
|
|
57
|
+
across the hazo workspace have been backfilled in this release.
|
|
58
|
+
|
|
59
|
+
The `AutoTestRunner` renders a `▸/▾` caret toggle next to each case name. Clicking it expands a
|
|
60
|
+
doc panel showing the four fields as labeled sections (Description / Inputs / Expected outputs /
|
|
61
|
+
Caveats). Failed-case error output and "Copy prompt" behaviour are unchanged.
|
|
62
|
+
|
|
63
|
+
**Exports added:** `CaseDoc` is now part of the public `hazo_ui/test-harness` surface.
|
|
64
|
+
|
|
65
|
+
```ts
|
|
66
|
+
import { registerScenario, type CaseDoc } from "hazo_ui/test-harness";
|
|
67
|
+
|
|
68
|
+
registerScenario("my-pkg", {
|
|
69
|
+
name: "My Package",
|
|
70
|
+
pkg: "my-pkg",
|
|
71
|
+
cases: [
|
|
72
|
+
{
|
|
73
|
+
name: "creates a record",
|
|
74
|
+
doc: {
|
|
75
|
+
description: "Verifies that createRecord() inserts a row and returns the new ID.",
|
|
76
|
+
inputs: "A mock DB adapter seeded with an empty table; payload { title: 'hello' }.",
|
|
77
|
+
expectedOutputs: "Resolved string ID, table row count increases to 1.",
|
|
78
|
+
caveats: "None",
|
|
79
|
+
},
|
|
80
|
+
run: async () => { /* ... */ },
|
|
81
|
+
},
|
|
82
|
+
],
|
|
83
|
+
});
|
|
84
|
+
```
|
|
85
|
+
|
|
8
86
|
## v3.2.0 — 2026-05-31
|
|
9
87
|
|
|
10
88
|
**New:** `MarkdownEditor` — a generic, SSR-safe Markdown/MDX editor.
|
package/README.md
CHANGED
|
@@ -3285,6 +3285,47 @@ try { await sync(); } catch (e) {
|
|
|
3285
3285
|
|
|
3286
3286
|
Also exports `rawToast` (re-export of sonner's `toast`) for advanced use cases.
|
|
3287
3287
|
|
|
3288
|
+
### useWakeLock / use_wake_lock
|
|
3289
|
+
|
|
3290
|
+
Screen Wake Lock API wrapper. Prevents screen sleep while the lock is held. Automatically
|
|
3291
|
+
reacquires when the tab becomes visible again. Returns `supported: false` in environments
|
|
3292
|
+
that don't implement the API (SSR, older browsers).
|
|
3293
|
+
|
|
3294
|
+
**Imperative variant** (`useWakeLock`) — call `request()` / `release()` directly:
|
|
3295
|
+
|
|
3296
|
+
```ts
|
|
3297
|
+
import { useWakeLock } from "hazo_ui";
|
|
3298
|
+
const { supported, acquired, request, release } = useWakeLock();
|
|
3299
|
+
```
|
|
3300
|
+
|
|
3301
|
+
**Declarative variant** (`use_wake_lock`) — hold the lock while a condition is true:
|
|
3302
|
+
|
|
3303
|
+
```ts
|
|
3304
|
+
import { use_wake_lock } from "hazo_ui";
|
|
3305
|
+
use_wake_lock(timer.is_running); // acquires when true, releases when false
|
|
3306
|
+
```
|
|
3307
|
+
|
|
3308
|
+
### useFullscreen / use_fullscreen
|
|
3309
|
+
|
|
3310
|
+
Fullscreen API wrapper. Syncs `isFullscreen`/`is_fullscreen` with the native
|
|
3311
|
+
`fullscreenchange` event; SSR-safe.
|
|
3312
|
+
|
|
3313
|
+
**Explicit-ref variant** (`useFullscreen`) — pass your own element ref:
|
|
3314
|
+
|
|
3315
|
+
```ts
|
|
3316
|
+
import { useFullscreen } from "hazo_ui";
|
|
3317
|
+
const container_ref = useRef<HTMLDivElement>(null);
|
|
3318
|
+
const { isFullscreen, toggle } = useFullscreen(container_ref);
|
|
3319
|
+
```
|
|
3320
|
+
|
|
3321
|
+
**Self-binding variant** (`use_fullscreen`) — ref created and returned internally:
|
|
3322
|
+
|
|
3323
|
+
```ts
|
|
3324
|
+
import { use_fullscreen } from "hazo_ui";
|
|
3325
|
+
const { is_fullscreen, toggle, ref } = use_fullscreen();
|
|
3326
|
+
return <div ref={ref}><button onClick={toggle}>Fullscreen</button></div>;
|
|
3327
|
+
```
|
|
3328
|
+
|
|
3288
3329
|
### useLoadingState
|
|
3289
3330
|
|
|
3290
3331
|
Hook that returns a controlled loading flag plus an async wrapper.
|
|
@@ -3920,13 +3961,18 @@ export default function RootLayout({ children }) {
|
|
|
3920
3961
|
// test-app/scenarios/my_feature.ts
|
|
3921
3962
|
import { registerScenario, assertEqual } from 'hazo_ui/test-harness';
|
|
3922
3963
|
|
|
3923
|
-
registerScenario({
|
|
3924
|
-
id: 'my_feature',
|
|
3964
|
+
registerScenario('my_feature', {
|
|
3925
3965
|
name: 'My Feature',
|
|
3926
3966
|
pkg: 'my_pkg',
|
|
3927
3967
|
cases: [
|
|
3928
3968
|
{
|
|
3929
3969
|
name: 'returns correct value',
|
|
3970
|
+
doc: {
|
|
3971
|
+
description: 'Verifies that myFunction adds two numbers correctly.',
|
|
3972
|
+
inputs: 'myFunction(1, 2)',
|
|
3973
|
+
expectedOutputs: 'Returns 3.',
|
|
3974
|
+
caveats: 'None',
|
|
3975
|
+
},
|
|
3930
3976
|
run: async () => {
|
|
3931
3977
|
const result = myFunction(1, 2);
|
|
3932
3978
|
assertEqual(result, 3, 'should add two numbers');
|
|
@@ -3934,6 +3980,12 @@ registerScenario({
|
|
|
3934
3980
|
},
|
|
3935
3981
|
{
|
|
3936
3982
|
name: 'throws on invalid input',
|
|
3983
|
+
doc: {
|
|
3984
|
+
description: 'Verifies that myFunction rejects null as the first argument.',
|
|
3985
|
+
inputs: 'myFunction(null, 2)',
|
|
3986
|
+
expectedOutputs: 'Throws an error containing "invalid input".',
|
|
3987
|
+
caveats: 'None',
|
|
3988
|
+
},
|
|
3937
3989
|
run: async () => {
|
|
3938
3990
|
await assertThrows(() => myFunction(null, 2), 'invalid input');
|
|
3939
3991
|
},
|
|
@@ -3954,6 +4006,22 @@ export default function MyFeaturePage() {
|
|
|
3954
4006
|
}
|
|
3955
4007
|
```
|
|
3956
4008
|
|
|
4009
|
+
### Case documentation (`doc` — required)
|
|
4010
|
+
|
|
4011
|
+
Every case **must** include a `doc: CaseDoc` field. This is enforced at the TypeScript level — omitting it is a compile error. The `AutoTestRunner` surfaces it as a `▸/▾` per-case accordion so reviewers can read what each test verifies without opening the source file.
|
|
4012
|
+
|
|
4013
|
+
```ts
|
|
4014
|
+
import type { CaseDoc } from 'hazo_ui/test-harness';
|
|
4015
|
+
|
|
4016
|
+
// All four fields are required strings:
|
|
4017
|
+
const doc: CaseDoc = {
|
|
4018
|
+
description: 'What this test verifies, in plain language.',
|
|
4019
|
+
inputs: 'Inputs / preconditions fed in (URL, payload, fixture, state).',
|
|
4020
|
+
expectedOutputs: 'What is asserted on success.',
|
|
4021
|
+
caveats: 'None', // use "None" when nothing notable applies
|
|
4022
|
+
};
|
|
4023
|
+
```
|
|
4024
|
+
|
|
3957
4025
|
### Copying failures as a Claude prompt
|
|
3958
4026
|
|
|
3959
4027
|
`CopyAllFailuresButton` copies all failed cases as a structured prompt with 8 sections (what-went-wrong, expected/actual/diff, test code, code under test, error chain, context, ring buffer). Place it in your sidebar or test page header.
|
package/SETUP_CHECKLIST.md
CHANGED
|
@@ -258,8 +258,9 @@ import {
|
|
|
258
258
|
// Import celebration (v2.18.0)
|
|
259
259
|
import { CelebrationProvider, celebrate, CELEBRATION_GRADIENT } from 'hazo_ui';
|
|
260
260
|
|
|
261
|
-
// Import test harness (v3.
|
|
262
|
-
|
|
261
|
+
// Import test harness (v3.3.0) — test-app only, never in production bundles
|
|
262
|
+
// Note: every Case must include a `doc: CaseDoc` field (required since v3.3.0)
|
|
263
|
+
import { AutoTestProvider, AutoTestRunner, SidebarLayout, AppSidebar, registerScenario, assertEqual, type CaseDoc } from 'hazo_ui/test-harness';
|
|
263
264
|
```
|
|
264
265
|
|
|
265
266
|
**Toaster setup**: Mount `<HazoUiToaster />` once at the root of your app (e.g., in `layout.tsx`) so `successToast()` / `errorToast()` calls have somewhere to render.
|
package/dist/index.cjs
CHANGED
|
@@ -74,6 +74,7 @@ var TogglePrimitive = require('@radix-ui/react-toggle');
|
|
|
74
74
|
var ToggleGroupPrimitive = require('@radix-ui/react-toggle-group');
|
|
75
75
|
var AlertDialogPrimitive = require('@radix-ui/react-alert-dialog');
|
|
76
76
|
var sonner = require('sonner');
|
|
77
|
+
var client$1 = require('hazo_state/client');
|
|
77
78
|
|
|
78
79
|
function _interopDefault (e) { return e && e.__esModule ? e : { default: e }; }
|
|
79
80
|
|
|
@@ -7999,6 +8000,18 @@ function useFullscreen(elementRef) {
|
|
|
7999
8000
|
}, [enter, exit]);
|
|
8000
8001
|
return { isFullscreen: is_fullscreen, enter, exit, toggle };
|
|
8001
8002
|
}
|
|
8003
|
+
function use_wake_lock(active) {
|
|
8004
|
+
const { acquired, request, release } = useWakeLock();
|
|
8005
|
+
React26.useEffect(() => {
|
|
8006
|
+
if (active && !acquired) void request();
|
|
8007
|
+
if (!active && acquired) void release();
|
|
8008
|
+
}, [active, acquired, request, release]);
|
|
8009
|
+
}
|
|
8010
|
+
function use_fullscreen() {
|
|
8011
|
+
const ref = React26.useRef(null);
|
|
8012
|
+
const { isFullscreen, toggle } = useFullscreen(ref);
|
|
8013
|
+
return { is_fullscreen: isFullscreen, toggle, ref };
|
|
8014
|
+
}
|
|
8002
8015
|
function KanbanCard({
|
|
8003
8016
|
item,
|
|
8004
8017
|
renderCard,
|
|
@@ -10701,6 +10714,177 @@ function CelebrationModalInner({
|
|
|
10701
10714
|
);
|
|
10702
10715
|
}
|
|
10703
10716
|
|
|
10717
|
+
// src/components/hazo_ui_eta_progress/eta.ts
|
|
10718
|
+
function median(values) {
|
|
10719
|
+
if (values.length === 0) return 0;
|
|
10720
|
+
const sorted = [...values].sort((a, b) => a - b);
|
|
10721
|
+
const mid = Math.floor(sorted.length / 2);
|
|
10722
|
+
return sorted.length % 2 === 0 ? (sorted[mid - 1] + sorted[mid]) / 2 : sorted[mid];
|
|
10723
|
+
}
|
|
10724
|
+
function computeEta(durationWindow, unitCount, concurrency = 1, fallbackUnitMs = 5e3) {
|
|
10725
|
+
const unitMs = durationWindow.length > 0 ? median(durationWindow) : fallbackUnitMs;
|
|
10726
|
+
return unitMs * Math.ceil(unitCount / Math.max(1, concurrency));
|
|
10727
|
+
}
|
|
10728
|
+
function easeToward(elapsed, eta, maxCap = 0.95) {
|
|
10729
|
+
if (eta <= 0 || elapsed <= 0) return 0;
|
|
10730
|
+
const t = elapsed / eta;
|
|
10731
|
+
return maxCap * (1 - Math.exp(-1.5 * t));
|
|
10732
|
+
}
|
|
10733
|
+
function HazoUiProgressBar({
|
|
10734
|
+
value,
|
|
10735
|
+
label,
|
|
10736
|
+
showPercent = false,
|
|
10737
|
+
size = 8,
|
|
10738
|
+
className
|
|
10739
|
+
}) {
|
|
10740
|
+
const pct = Math.round(Math.min(1, Math.max(0, value)) * 100);
|
|
10741
|
+
return /* @__PURE__ */ jsxRuntime.jsxs("div", { className: cn("w-full", className), children: [
|
|
10742
|
+
(label || showPercent) && /* @__PURE__ */ jsxRuntime.jsxs("div", { className: "flex items-center justify-between mb-1", children: [
|
|
10743
|
+
label && /* @__PURE__ */ jsxRuntime.jsx("span", { className: "text-sm text-muted-foreground", children: label }),
|
|
10744
|
+
showPercent && /* @__PURE__ */ jsxRuntime.jsxs("span", { className: "text-xs text-muted-foreground tabular-nums", children: [
|
|
10745
|
+
pct,
|
|
10746
|
+
"%"
|
|
10747
|
+
] })
|
|
10748
|
+
] }),
|
|
10749
|
+
/* @__PURE__ */ jsxRuntime.jsx(
|
|
10750
|
+
"div",
|
|
10751
|
+
{
|
|
10752
|
+
role: "progressbar",
|
|
10753
|
+
"aria-valuenow": pct,
|
|
10754
|
+
"aria-valuemin": 0,
|
|
10755
|
+
"aria-valuemax": 100,
|
|
10756
|
+
"aria-label": label,
|
|
10757
|
+
className: "w-full rounded-full overflow-hidden bg-muted",
|
|
10758
|
+
style: { height: size },
|
|
10759
|
+
children: /* @__PURE__ */ jsxRuntime.jsx(
|
|
10760
|
+
"div",
|
|
10761
|
+
{
|
|
10762
|
+
className: "h-full rounded-full bg-accent transition-[width] duration-200 ease-out motion-reduce:transition-none",
|
|
10763
|
+
style: { width: `${pct}%` }
|
|
10764
|
+
}
|
|
10765
|
+
)
|
|
10766
|
+
}
|
|
10767
|
+
)
|
|
10768
|
+
] });
|
|
10769
|
+
}
|
|
10770
|
+
function useEtaProgress(opts) {
|
|
10771
|
+
const {
|
|
10772
|
+
unitCount,
|
|
10773
|
+
concurrency = 1,
|
|
10774
|
+
fallbackUnitMs = 5e3,
|
|
10775
|
+
loadDurations,
|
|
10776
|
+
appendDuration
|
|
10777
|
+
} = opts;
|
|
10778
|
+
const [value, setValue] = React26__namespace.useState(0);
|
|
10779
|
+
const stateRef = React26__namespace.useRef({
|
|
10780
|
+
started: false,
|
|
10781
|
+
finished: false,
|
|
10782
|
+
startTime: 0,
|
|
10783
|
+
unitsDone: 0,
|
|
10784
|
+
unitTimestamps: [],
|
|
10785
|
+
// timestamps of each unitDone() call
|
|
10786
|
+
eta: 0,
|
|
10787
|
+
rafId: 0
|
|
10788
|
+
});
|
|
10789
|
+
const stop = React26__namespace.useCallback(() => {
|
|
10790
|
+
if (stateRef.current.rafId) {
|
|
10791
|
+
cancelAnimationFrame(stateRef.current.rafId);
|
|
10792
|
+
stateRef.current.rafId = 0;
|
|
10793
|
+
}
|
|
10794
|
+
}, []);
|
|
10795
|
+
React26__namespace.useEffect(() => stop, [stop]);
|
|
10796
|
+
const tick = React26__namespace.useCallback(() => {
|
|
10797
|
+
const s = stateRef.current;
|
|
10798
|
+
if (s.finished || !s.started) return;
|
|
10799
|
+
const elapsed = Date.now() - s.startTime;
|
|
10800
|
+
const timeValue = easeToward(elapsed, s.eta);
|
|
10801
|
+
const unitValue = unitCount > 0 ? s.unitsDone / unitCount : 0;
|
|
10802
|
+
setValue(Math.max(timeValue, unitValue));
|
|
10803
|
+
s.rafId = requestAnimationFrame(tick);
|
|
10804
|
+
}, [unitCount]);
|
|
10805
|
+
const start = React26__namespace.useCallback(() => {
|
|
10806
|
+
const s = stateRef.current;
|
|
10807
|
+
if (s.started) return;
|
|
10808
|
+
const window2 = loadDurations();
|
|
10809
|
+
const eta = computeEta(window2, unitCount, concurrency, fallbackUnitMs);
|
|
10810
|
+
s.started = true;
|
|
10811
|
+
s.finished = false;
|
|
10812
|
+
s.startTime = Date.now();
|
|
10813
|
+
s.unitsDone = 0;
|
|
10814
|
+
s.unitTimestamps = [];
|
|
10815
|
+
s.eta = eta;
|
|
10816
|
+
stop();
|
|
10817
|
+
s.rafId = requestAnimationFrame(tick);
|
|
10818
|
+
}, [loadDurations, unitCount, concurrency, fallbackUnitMs, stop, tick]);
|
|
10819
|
+
const unitDone = React26__namespace.useCallback(() => {
|
|
10820
|
+
const s = stateRef.current;
|
|
10821
|
+
if (!s.started || s.finished) return;
|
|
10822
|
+
s.unitsDone = Math.min(s.unitsDone + 1, unitCount);
|
|
10823
|
+
s.unitTimestamps.push(Date.now());
|
|
10824
|
+
}, [unitCount]);
|
|
10825
|
+
const finish = React26__namespace.useCallback(() => {
|
|
10826
|
+
const s = stateRef.current;
|
|
10827
|
+
if (s.finished) return;
|
|
10828
|
+
s.finished = true;
|
|
10829
|
+
stop();
|
|
10830
|
+
setValue(1);
|
|
10831
|
+
if (s.started && s.unitTimestamps.length > 0) {
|
|
10832
|
+
const totalMs = Date.now() - s.startTime;
|
|
10833
|
+
const perUnitMs = totalMs / Math.ceil(unitCount / Math.max(1, concurrency));
|
|
10834
|
+
appendDuration(perUnitMs);
|
|
10835
|
+
}
|
|
10836
|
+
s.started = false;
|
|
10837
|
+
s.unitsDone = 0;
|
|
10838
|
+
}, [stop, unitCount, concurrency, appendDuration]);
|
|
10839
|
+
return { value, start, unitDone, finish };
|
|
10840
|
+
}
|
|
10841
|
+
function HazoUiEtaProgress({
|
|
10842
|
+
estimateKey,
|
|
10843
|
+
unitCount,
|
|
10844
|
+
concurrency = 1,
|
|
10845
|
+
windowSize = 5,
|
|
10846
|
+
fallbackUnitMs = 5e3,
|
|
10847
|
+
level = "global",
|
|
10848
|
+
label,
|
|
10849
|
+
endpoint,
|
|
10850
|
+
handleRef,
|
|
10851
|
+
className
|
|
10852
|
+
}) {
|
|
10853
|
+
const { value: stored, append } = client$1.useHazoState(estimateKey, {
|
|
10854
|
+
level,
|
|
10855
|
+
fallback: [],
|
|
10856
|
+
...endpoint ? { endpoint } : {}
|
|
10857
|
+
});
|
|
10858
|
+
const durationWindow = Array.isArray(stored) ? stored : [];
|
|
10859
|
+
const loadDurations = React26__namespace.useCallback(() => durationWindow, [durationWindow]);
|
|
10860
|
+
const appendDuration = React26__namespace.useCallback(
|
|
10861
|
+
(ms) => {
|
|
10862
|
+
append(ms, windowSize);
|
|
10863
|
+
},
|
|
10864
|
+
[append, windowSize]
|
|
10865
|
+
);
|
|
10866
|
+
const handle = useEtaProgress({
|
|
10867
|
+
unitCount,
|
|
10868
|
+
concurrency,
|
|
10869
|
+
fallbackUnitMs,
|
|
10870
|
+
loadDurations,
|
|
10871
|
+
appendDuration
|
|
10872
|
+
});
|
|
10873
|
+
React26__namespace.useEffect(() => {
|
|
10874
|
+
if (handleRef) {
|
|
10875
|
+
handleRef.current = handle;
|
|
10876
|
+
}
|
|
10877
|
+
}, [handleRef, handle]);
|
|
10878
|
+
return /* @__PURE__ */ jsxRuntime.jsx(
|
|
10879
|
+
HazoUiProgressBar,
|
|
10880
|
+
{
|
|
10881
|
+
value: handle.value,
|
|
10882
|
+
label,
|
|
10883
|
+
className
|
|
10884
|
+
}
|
|
10885
|
+
);
|
|
10886
|
+
}
|
|
10887
|
+
|
|
10704
10888
|
Object.defineProperty(exports, "rawToast", {
|
|
10705
10889
|
enumerable: true,
|
|
10706
10890
|
get: function () { return sonner.toast; }
|
|
@@ -10783,6 +10967,7 @@ exports.HazoUiDialogPortal = DialogPortal;
|
|
|
10783
10967
|
exports.HazoUiDialogRoot = Dialog;
|
|
10784
10968
|
exports.HazoUiDialogTitle = DialogTitle;
|
|
10785
10969
|
exports.HazoUiDialogTrigger = DialogTrigger;
|
|
10970
|
+
exports.HazoUiEtaProgress = HazoUiEtaProgress;
|
|
10786
10971
|
exports.HazoUiFlexInput = HazoUiFlexInput;
|
|
10787
10972
|
exports.HazoUiFlexRadio = HazoUiFlexRadio;
|
|
10788
10973
|
exports.HazoUiKanban = HazoUiKanban;
|
|
@@ -10790,6 +10975,7 @@ exports.HazoUiKanbanFilter = HazoUiKanbanFilter;
|
|
|
10790
10975
|
exports.HazoUiMultiFilterDialog = HazoUiMultiFilterDialog;
|
|
10791
10976
|
exports.HazoUiMultiSortDialog = HazoUiMultiSortDialog;
|
|
10792
10977
|
exports.HazoUiPillRadio = HazoUiPillRadio;
|
|
10978
|
+
exports.HazoUiProgressBar = HazoUiProgressBar;
|
|
10793
10979
|
exports.HazoUiRte = HazoUiRte;
|
|
10794
10980
|
exports.HazoUiTable = HazoUiTable;
|
|
10795
10981
|
exports.HazoUiTextarea = HazoUiTextarea;
|
|
@@ -10863,12 +11049,15 @@ exports.applyKanbanFilter = applyKanbanFilter;
|
|
|
10863
11049
|
exports.buttonGroupVariants = buttonGroupVariants;
|
|
10864
11050
|
exports.celebrate = celebrate;
|
|
10865
11051
|
exports.cn = cn;
|
|
11052
|
+
exports.computeEta = computeEta;
|
|
10866
11053
|
exports.create_command_suggestion_extension = create_command_suggestion_extension;
|
|
11054
|
+
exports.easeToward = easeToward;
|
|
10867
11055
|
exports.errorToast = errorToast;
|
|
10868
11056
|
exports.format_num = format_num;
|
|
10869
11057
|
exports.generateUUID = generateUUID;
|
|
10870
11058
|
exports.get_hazo_ui_config = get_hazo_ui_config;
|
|
10871
11059
|
exports.get_logger = get_logger;
|
|
11060
|
+
exports.median = median;
|
|
10872
11061
|
exports.parse_commands_from_text = parse_commands_from_text;
|
|
10873
11062
|
exports.pick_x_label_indices = pick_x_label_indices;
|
|
10874
11063
|
exports.reset_hazo_ui_config = reset_hazo_ui_config;
|
|
@@ -10882,6 +11071,7 @@ exports.useClickOutside = useClickOutside;
|
|
|
10882
11071
|
exports.useCopyToClipboard = useCopyToClipboard;
|
|
10883
11072
|
exports.useDebounce = useDebounce;
|
|
10884
11073
|
exports.useErrorDisplay = useErrorDisplay;
|
|
11074
|
+
exports.useEtaProgress = useEtaProgress;
|
|
10885
11075
|
exports.useFullscreen = useFullscreen;
|
|
10886
11076
|
exports.useIsMobile = useIsMobile;
|
|
10887
11077
|
exports.useLoadingState = useLoadingState;
|
|
@@ -10890,5 +11080,7 @@ exports.useMediaQuery = useMediaQuery;
|
|
|
10890
11080
|
exports.useSessionStorage = useSessionStorage;
|
|
10891
11081
|
exports.useViewport = useViewport;
|
|
10892
11082
|
exports.useWakeLock = useWakeLock;
|
|
11083
|
+
exports.use_fullscreen = use_fullscreen;
|
|
11084
|
+
exports.use_wake_lock = use_wake_lock;
|
|
10893
11085
|
//# sourceMappingURL=index.cjs.map
|
|
10894
11086
|
//# sourceMappingURL=index.cjs.map
|