@owlmeans/web-panel 0.1.18-rc.30 → 0.1.18-rc.32

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.
Files changed (56) hide show
  1. package/README.md +2 -2
  2. package/agent-meta/manifest.json +2 -2
  3. package/agent-meta/skills/web-panel/SKILL.md +118 -19
  4. package/build/@/components/ui/button.d.ts +2 -2
  5. package/build/auth/context.d.ts.map +1 -1
  6. package/build/auth/entrypoints.d.ts +1 -1
  7. package/build/auth/entrypoints.d.ts.map +1 -1
  8. package/build/components/form/button/component.js.map +1 -1
  9. package/build/components/form/component.js.map +1 -1
  10. package/build/components/helper.d.ts.map +1 -1
  11. package/build/components/login/append.d.ts.map +1 -1
  12. package/build/context.d.ts.map +1 -1
  13. package/build/entrypoints.d.ts +1 -1
  14. package/build/entrypoints.d.ts.map +1 -1
  15. package/build/hooks/index.d.ts +2 -0
  16. package/build/hooks/index.d.ts.map +1 -0
  17. package/build/hooks/index.js +2 -0
  18. package/build/hooks/index.js.map +1 -0
  19. package/build/hooks/use-mobile.d.ts +16 -0
  20. package/build/hooks/use-mobile.d.ts.map +1 -0
  21. package/build/hooks/use-mobile.js +30 -0
  22. package/build/hooks/use-mobile.js.map +1 -0
  23. package/build/index.d.ts +2 -0
  24. package/build/index.d.ts.map +1 -1
  25. package/build/index.js +2 -0
  26. package/build/index.js.map +1 -1
  27. package/build/jobs/component.d.ts +19 -0
  28. package/build/jobs/component.d.ts.map +1 -0
  29. package/build/jobs/component.js +55 -0
  30. package/build/jobs/component.js.map +1 -0
  31. package/build/jobs/index.d.ts +4 -0
  32. package/build/jobs/index.d.ts.map +1 -0
  33. package/build/jobs/index.js +3 -0
  34. package/build/jobs/index.js.map +1 -0
  35. package/build/jobs/toasts.d.ts +14 -0
  36. package/build/jobs/toasts.d.ts.map +1 -0
  37. package/build/jobs/toasts.js +39 -0
  38. package/build/jobs/toasts.js.map +1 -0
  39. package/build/jobs/types.d.ts +21 -0
  40. package/build/jobs/types.d.ts.map +1 -0
  41. package/build/jobs/types.js +2 -0
  42. package/build/jobs/types.js.map +1 -0
  43. package/build/main.d.ts.map +1 -1
  44. package/build/utils.d.ts +13 -0
  45. package/build/utils.d.ts.map +1 -0
  46. package/build/utils.js +14 -0
  47. package/build/utils.js.map +1 -0
  48. package/package.json +35 -27
  49. package/src/hooks/index.ts +1 -0
  50. package/src/hooks/use-mobile.ts +35 -0
  51. package/src/index.ts +2 -0
  52. package/src/jobs/component.tsx +78 -0
  53. package/src/jobs/index.ts +4 -0
  54. package/src/jobs/toasts.ts +41 -0
  55. package/src/jobs/types.ts +23 -0
  56. package/src/utils.ts +14 -0
package/README.md CHANGED
@@ -15,7 +15,7 @@ instead of Material UI.
15
15
  ## Install
16
16
 
17
17
  ```sh
18
- bun add @owlmeans/web-panel
18
+ bun add @owlmeans/web-panel@^0.1.18-rc.31
19
19
  ```
20
20
 
21
21
  Peer requirements (the consuming app provides these): `react`, `react-dom`,
@@ -213,7 +213,7 @@ This package ships embedded agent skills under `agent-meta/`. After installing y
213
213
  your project's skill store (`.agents/skills/`):
214
214
 
215
215
  ```sh
216
- npx @owlmeans/agent-skills
216
+ npx @owlmeans/agent-skills@^0.1.18-rc.12
217
217
  ```
218
218
 
219
219
  The embedded files are version-matched to this package release. Do not edit them
@@ -1,8 +1,8 @@
1
1
  {
2
2
  "schemaVersion": 2,
3
3
  "package": "@owlmeans/web-panel",
4
- "version": "0.1.18-rc.30",
5
- "generatedAt": "2026-09-01T16:49:00.430Z",
4
+ "version": "0.1.18-rc.32",
5
+ "generatedAt": "2026-09-04T22:43:25.453Z",
6
6
  "canonicalRepo": "https://github.com/owlmeans/common",
7
7
  "entries": [
8
8
  {
@@ -8,7 +8,7 @@ user-invocable: false
8
8
  # @owlmeans/web-panel
9
9
 
10
10
  **Layer:** Web (React)
11
- **Install:** `"@owlmeans/web-panel": "^0.1.18-rc.30"` in `dependencies`
11
+ **Install:** `"@owlmeans/web-panel": "^0.1.18-rc.32"` in `dependencies`
12
12
 
13
13
  ## Key Exports
14
14
 
@@ -20,15 +20,28 @@ user-invocable: false
20
20
  | `Toaster` | The application's toast surface — mounted once, in the layout |
21
21
  | `Link` | An `<a>` addressing an entrypoint alias (or a literal `src`), with the label taken from i18n |
22
22
  | `LoginScreen` / `LocalizedLoginScreen` / `appendLoginScreen` | The identity-provider choice screen — see `login-methods` |
23
- | `components` submodule | shadcn/Radix panel/form components |
23
+ | `render(context, opts?)` | Mounts the tree inside `PanelApp`, with the browser language detector installed on the i18n instance. `opts` is `RenderOptions` plus `rootClassName` |
24
+ | `PanelApp` | That wrapper on its own — the themed root `div` plus the i18n provider — for a host that mounts the tree itself |
25
+ | `useContext<C, T>()` | The current context, from React. `AppContext` adds `context.flow()` over `@owlmeans/web-client`'s |
26
+ | `entrypoints` | The base declaration list — `@owlmeans/web-client`'s plus `@owlmeans/api-config-client`'s. Compose the app's own over it |
27
+ | `Block` / `Text` / `Status` | The shadcn `Card` panel with an optional `Actions` footer, a heading/paragraph whose copy comes from the panel namespace, and the shadcn `Alert` resolving a `ResilientError` to a translated message |
28
+ | `Form` / `TextInput` / `Button` / `SubmitButton` / `ButtonSelector` | The web form family. `Form` builds its own `useForm` + `ajvResolver` and borrows only `FormContext` and `schemaToFormDefault` from `@owlmeans/client-panel`; `TextInput` drives `react-hook-form`'s `Controller` directly, and the buttons call `handleSubmit` directly — none of them wraps `ClientForm`, `InputCtrl` or `ActionCtrl` |
29
+ | `ImageUploader` / `Layout` | The uploader in a drop target with a preview, and a plain content wrapper (the shell is `NavLayout`) |
30
+ | `scalingToStyles(h, v)` | `BlockScaling` → the width/height utility classes the panels share |
31
+ | `cn(...inputs)` | The class-name merger the components are written against — an app never re-declares it |
32
+ | `useIsMobile()` / `MOBILE_BREAKPOINT` | Viewport narrower than Tailwind's `md` (768), matched with `matchMedia` |
33
+ | `useBreakPoint()` | The current Tailwind breakpoint name, tracked on `resize` (`lg` when there is no `window`) |
34
+ | `useMapBreakpoint(map, def?, breakpoint?)` | The `map` entry for the current breakpoint (or for the `breakpoint` passed), falling back to `def`. It **throws a `SyntaxError`** when neither yields a value, so give it a `def` or cover every breakpoint |
24
35
  | Re-exports from `@owlmeans/client-panel` | Cross-platform panel primitives, incl. `usePanelNav` and the `PanelNav*` types |
25
- | Re-exports from `@owlmeans/client` / `@owlmeans/client-entrypoint` | `entrypoint`, `elevate`, `handler`, `route`, `frontend`, `guard`, `useNavigate`, `useEntrypoint`, `useValue` |
26
- | `main`, `exports`, `context`, `entrypoints`, `types` | Wiring helpers |
36
+ | Re-exports from `@owlmeans/client` / `@owlmeans/client-entrypoint` / `@owlmeans/route` | `entrypoint`, `elevate`, `handler`, `provideRequest`, `stab`, `route`, `croute`, `frontend`, `guard`, `useNavigate`, `useEntrypoint`, `useValue` |
37
+ | Re-exports from the surrounding layers | `config`, `service`, `addWebService`, `AppType` / `HOME` / `ROOT` / `BASE` / `GUEST`, `DISPATCHER`, `CAUTHEN_FLOW_ENTER`, `DAUTH_GUARD`, `setupExternalAuthentication`, `Dispatcher`, `appendWebAuthService`, `flow` / `configureFlows` / `useFlow` / `FLOW_PARAM` / `SERVICE_PARAM`, `useI18n*` / `useLanguage` / `composePrefix`, `addI18nApp` / `addI18nLib` / `SUPPORTED_LNGS` |
27
38
 
28
39
  ## Subpath Exports
29
40
 
30
41
  - `./auth` — auth panel components for web
31
42
  - `./auth/entrypoints` — auth panel entrypoint declarations
43
+ - `./consent` — the cookie consent dialog and policy, bound to this app's i18n
44
+ - `./jobs` — `JobProgress`, `JobStatus`, `useJobToasts` over `@owlmeans/queue` records
32
45
 
33
46
  ## Usage
34
47
 
@@ -94,7 +107,7 @@ header. Both render the same items; only one is visible at a time.
94
107
  | `NavLayout` | `nav: PanelNavConfig`, `translate?`, `title?: ReactNode`, `home?: string` (brand target — defaults to the first section's first item), `actions?: ReactNode`, `footer?: PanelNavLink[] \| ReactNode`, `headerClassName?`, `contentClassName?`, `containerClassName?`, `className?`, `style?` |
95
108
  | `TopNav` | `config: PanelNavConfig`, `translate?`, `ariaLabel?`, `className?`, `style?` |
96
109
  | `SideNav` | the same, plus `variant?: 'side' \| 'bar'` |
97
- | `Footer` | `links?: PanelNavLink[]`, `translate?`, `children?`, `className?`, `style?` |
110
+ | `Footer` | `links?: PanelNavLink[]`, `translate?`, `containerClassName?` (the shell's rhythm, so the footer row lines up with the header and content), `children?`, `className?`, `style?` |
98
111
 
99
112
  **The style slots are REGIONS, and each region is its own SURFACE.** `className` is the root —
100
113
  the full-height page *behind* the header, side menu and footer. `headerClassName` is the sticky
@@ -126,12 +139,13 @@ width-only override permanently.
126
139
  (`bg-secondary text-secondary-foreground`) — never by colouring the root and expecting the bar
127
140
  to follow.
128
141
 
129
- **The shell reads exactly five theme variables**: `--background` (page and top bar),
130
- `--foreground` (active section link), `--muted-foreground` (resting section links) and
131
- `--accent`/`--accent-foreground` (active side-menu item). It reads **no `--sidebar*` variable at
132
- all**. So `--muted-foreground` is not merely the text colour of the `--muted` surface — it is
133
- secondary text sitting directly on `--background`, and a theme that lightens it to suit a dark
134
- muted panel loses its top menu.
142
+ **The shell reads exactly these colour variables**: `--background` (page and top bar),
143
+ `--foreground` (active section link), `--muted-foreground` (resting section links),
144
+ `--accent`/`--accent-foreground` (active side-menu item), `--border` (the header, side-menu and
145
+ footer rules) and `--primary` — the footer renders its entries through `Link`, which paints
146
+ `text-primary`. It reads **no `--sidebar*` variable at all**. So `--muted-foreground` is not merely
147
+ the text colour of the `--muted` surface — it is secondary text sitting directly on `--background`,
148
+ and a theme that lightens it to suit a dark muted panel loses its top menu.
135
149
 
136
150
  Rules that make the shell behave:
137
151
 
@@ -201,14 +215,85 @@ known — so never key a test or a layout on the anchor having an `href` synchro
201
215
  falls back to `modules.<alias>` when neither `name` nor `children` is given, `open` adds
202
216
  `target="_blank"` with `rel="noopener noreferrer"`, and `center` centres the text.
203
217
 
218
+ ### Forms — `Form`, `TextInput`, the buttons
219
+
220
+ `WebFormProps` is `@owlmeans/client-panel`'s `FormProps` plus `className` and `style`. `Form` holds
221
+ the whole model itself — `useForm` with `mode: 'all'`, `delayError: 300`, an `ajvResolver` over
222
+ `validation` with `coerceTypes` and the `ajv-formats` formats — and publishes it through
223
+ `FormProvider` plus `FormContext`, so every control below reads one form.
224
+
225
+ ```tsx
226
+ import { Form, TextInput, SubmitButton, Button } from '@owlmeans/web-panel'
227
+
228
+ <Form decorate validation={schema} onSubmit={async (data, update) => { await save(data); update(data) }}>
229
+ <TextInput name="email" label placeholder hint />
230
+ <TextInput name="password" type="password" label="Password" />
231
+ </Form>
232
+ ```
233
+
234
+ - **`decorate` switches the whole rendering.** With `decorate={true}` the fields go inside a shadcn
235
+ `Card`, the root error surfaces through `Status`, and a `SubmitButton` is rendered in the
236
+ `CardFooter` **whenever `onSubmit` is given** — the caller writes no action. Without it (the
237
+ default) `Form` is a bare flex column: no card, no root-error surface, no submit button, so the
238
+ caller renders its own action. `horizontal`/`vertical` scaling, `className` and `style` land on
239
+ the `Card` when decorated and on that column otherwise.
240
+ - **`formRef`** — a `useFormRef()` ref filled with `{ form, update, loader, error }`, which is how a
241
+ caller drives the form, flips the loader, or plants a field/root error from outside.
242
+ - **`TextInput` takes `label`, `placeholder` and `hint` as `string | boolean`.** `true` resolves
243
+ `<name>.label` / `<name>.placeholder` / `<name>.hint` from the form namespace; a string is used
244
+ verbatim; anything else renders nothing. It also takes `name`, `def`, `type` (any HTML input type,
245
+ default `text`) and `disableAutocomplete`. A field error replaces the hint line.
246
+ - **`Button`** takes a required `label`, `onClick`, `loader` (a `Toggleable` — open disables the
247
+ button and shows the spinner), `size` (`small`/`medium`/`large`), `fullWidth`, and `variant`,
248
+ which maps the MUI vocabulary onto shadcn (`contained` → `default`, `outlined` → `outline`,
249
+ `text` → `ghost`) and forwards a shadcn variant name unchanged.
250
+ - **`SubmitButton`** is that button bound to `handleSubmit`, taking `onSubmit` (or `onClick`) and a
251
+ `label` defaulting to `submit`. It resolves the label with the form `t` itself and passes it down
252
+ with `i18n.suppress` set, so the label is translated once.
253
+ - **`ButtonSelector`** renders one `Button` per entry of `options`, the one equal to `current`
254
+ `contained` and the rest `outlined`, calling `onSelect(option)`. `name` prefixes each option's
255
+ label key as `<name>.<option>`.
256
+
257
+ ## Subpath: `./jobs`
258
+
259
+ Three presentational pieces for a queue job, over `JobRecord` from `@owlmeans/queue`. They take
260
+ records — `@owlmeans/client-job`'s `useJobs()` maps straight onto them — and hold no store, no
261
+ socket and no strings of their own.
262
+
263
+ ```tsx
264
+ import { JobProgress, JobStatus, useJobToasts } from '@owlmeans/web-panel/jobs'
265
+
266
+ const jobs = useJobs().map(model => model.record)
267
+ useJobToasts(jobs)
268
+
269
+ <JobStatus job={job} labels={{ [JobState.Active]: t('jobs.running') }} />
270
+ <JobProgress job={job} />
271
+ ```
272
+
273
+ | Export | Description |
274
+ |---|---|
275
+ | `JobProgress` | The shadcn `Progress` bar. `job.progress` is read as a number, `{ percent }` or `{ done, total }`; anything else animates INDETERMINATE, because zero and "the processor never called `progress()`" look identical otherwise |
276
+ | `JobStatus` | The state pill. `data-state` carries the raw state, so a test never keys on the wording |
277
+ | `jobProgressValue(job)` | The percentage the bar shows, or `undefined` |
278
+ | `useJobToasts(jobs, opts?)` | One toast per job the first time it settles, on the `Toaster` the layout already mounts |
279
+
280
+ - **No packaged wording.** The states are broker vocabulary; the sentence an app wants for them
281
+ ("Queued", "Rendering", "Ready") is its own copy in its own namespace, so `JobStatus` takes a
282
+ `labels` map and otherwise renders the raw state — data, not an untranslated string.
283
+ - **`useJobToasts` never toasts on its first pass.** A screen opening onto a store seeded with
284
+ yesterday's finished jobs would fire a stack of them at once, so everything already settled at
285
+ mount is recorded as announced and only what settles afterwards is reported.
286
+ - It needs the same single `Toaster` as everything else — see above.
287
+
204
288
  ## Subpath: `./consent`
205
289
 
206
290
  `PanelCookieConsent` and `PanelCookiePolicy` — `@owlmeans/web-consent`'s components bound to this
207
291
  app's language and translations, falling through to the package's own seven-language bundle for
208
292
  every key the app has not overridden. See the `consent` skill.
209
293
 
210
- A re-export does not move Tailwind class strings, so a consumer still adds an `@source` for
211
- `@owlmeans/web-consent/build` as well as for this package's.
294
+ A re-export does not move Tailwind class strings, so a consumer adds a second `@source` for
295
+ `@owlmeans/web-consent` alongside this package's — pointing at **`src`**, for the reason spelled out
296
+ under *Consumer setup* below. Without it the dialog renders half-styled.
212
297
 
213
298
  ## Consumer setup — the `@` contract and Tailwind
214
299
 
@@ -217,22 +302,36 @@ its own shadcn copy. Vendor every primitive the package imports: `alert`, `butto
217
302
  `label`, `navigation-menu`, `progress` (plus `separator` if you use it), and add
218
303
  `@radix-ui/react-navigation-menu` alongside the other Radix peers.
219
304
 
220
- Then point Tailwind at the built package. Its oxide scanner reads the CSS root plus `@source`
221
- directives only, and excludes `node_modules` — so classes that exist **only** inside `web-panel`
222
- components (the whole navigation shell and footer) never reach the stylesheet, and the app renders
223
- an unstyled menu. In the app's Tailwind entry:
305
+ The vendored `@/lib/utils` stays — the package's own components resolve `cn` through it — but the
306
+ app's own components import `cn` from `@owlmeans/web-panel` instead of declaring a third copy. The
307
+ public export is a package-owned function, deliberately not a re-export of `@/lib/utils`: that
308
+ specifier is emitted verbatim and would resolve back to the consumer's file.
309
+
310
+ Then point Tailwind at the installed package's **`src`**. Its oxide scanner reads the CSS root
311
+ plus `@source` directives only, and excludes `node_modules` — so classes that exist **only** inside
312
+ `web-panel` components (the whole navigation shell and footer) never reach the stylesheet, and the
313
+ app renders an unstyled menu. In the app's Tailwind entry:
224
314
 
225
315
  ```css
226
316
  @import "tailwindcss";
227
317
 
228
- @source "../../../node_modules/@owlmeans/web-panel/build";
318
+ @source "../../../node_modules/@owlmeans/web-panel/src";
229
319
  ```
230
320
 
231
- Adjust the relative depth to your own layout; the target is the installed package's `build`.
321
+ Adjust the relative depth to your own layout. **Point at `src`, never at `build`:** the scanner
322
+ applies the `.gitignore` of whatever repository a path resolves into, and a linked `node_modules`
323
+ entry resolves into a monorepo whose `.gitignore` covers every package build directory — a `build`
324
+ source there scans zero files and reports nothing, while the shell renders unstyled with nothing to
325
+ blame. `src` is tracked in the repository and ships in the published tarball, so one path serves a
326
+ linked checkout and an npm install alike.
232
327
 
233
328
  ## Depends On
234
329
 
235
330
  - `@owlmeans/web-client`, `@owlmeans/client-panel`, `@owlmeans/client-i18n`, `@owlmeans/web-router`
331
+ - `@owlmeans/queue` — `JobRecord` / `JobState`, read by the `./jobs` subpath
236
332
  - Peers (app-provided): `react`, `react-dom`, `react-hook-form`, `tailwindcss`, `tailwind-merge`,
237
333
  `clsx`, `class-variance-authority`, `lucide-react`, `ajv`, and the `@radix-ui/react-*` primitives
238
334
  (`label`, `navigation-menu`, `progress`, `separator`, `slot`). No MUI, no react-router.
335
+ - `ajv-formats` is imported at module scope by the form model but is declared in no dependency
336
+ section of the manifest, which lists `ajv` alone. An install that does not otherwise pull it in
337
+ fails at import time, so declare `ajv-formats` next to `ajv` in the consuming application.
@@ -1,8 +1,8 @@
1
1
  import * as React from 'react';
2
2
  import { type VariantProps } from 'class-variance-authority';
3
3
  declare const buttonVariants: (props?: ({
4
- variant?: "default" | "destructive" | "outline" | "secondary" | "ghost" | "link" | null | undefined;
5
- size?: "default" | "sm" | "lg" | "icon" | null | undefined;
4
+ variant?: "default" | "destructive" | "ghost" | "link" | "outline" | "secondary" | null | undefined;
5
+ size?: "default" | "icon" | "lg" | "sm" | null | undefined;
6
6
  } & import("class-variance-authority/types").ClassProp) | undefined) => string;
7
7
  declare function Button({ className, variant, size, asChild, ...props }: React.ComponentProps<"button"> & VariantProps<typeof buttonVariants> & {
8
8
  asChild?: boolean;
@@ -1 +1 @@
1
- {"version":3,"file":"context.d.ts","sourceRoot":"","sources":["../../src/auth/context.ts"],"names":[],"mappings":"AAIA,OAAO,KAAK,EAAE,SAAS,IAAI,MAAM,EAAE,UAAU,IAAI,OAAO,EAAE,MAAM,sBAAsB,CAAA;AACtF,OAAO,EAAE,SAAS,EAAE,UAAU,EAAE,MAAM,YAAY,CAAA;AAIlD,eAAO,MAAM,WAAW,GAAI,CAAC,SAAS,MAAM,EAAE,CAAC,SAAS,OAAO,CAAC,CAAC,CAAC,EAAE,KAAK,CAAC,KAAG,CAY5E,CAAA;AAED,eAAO,MAAM,UAAU,GAAI,CAAC,SAAS,SAAS,GAAG,SAAS,EAAE,CAAC,SAAS,UAAU,CAAC,CAAC,CAAC,GAAG,UAAU,CAAC,CAAC,CAAC,OAAK,CAC9E,CAAA"}
1
+ {"version":3,"file":"context.d.ts","sourceRoot":"","sources":["../../src/auth/context.ts"],"names":[],"mappings":"AAIA,OAAO,KAAK,EAAE,SAAS,IAAI,MAAM,EAAE,UAAU,IAAI,OAAO,EAAE,MAAM,sBAAsB,CAAA;AACtF,OAAO,EAAE,SAAS,EAAE,UAAU,EAAE,MAAM,YAAY,CAAA;AAIlD,eAAO,MAAM,WAAW,GAAI,CAAC,SAAS,MAAM,EAAE,CAAC,SAAS,OAAO,CAAC,CAAC,CAAC,OAAO,CAAC,KAAG,CAY5E,CAAA;AAED,eAAO,MAAM,UAAU,GAAI,CAAC,SAAS,SAAS,GAAG,SAAS,EAAE,CAAC,SAAS,UAAU,CAAC,CAAC,CAAC,GAAG,UAAU,CAAC,CAAC,CAAC,OAAK,CAC9E,CAAA"}
@@ -1,2 +1,2 @@
1
- export declare const entrypoints: any[];
1
+ export declare const entrypoints: import("@owlmeans/entrypoint").CommonEntrypoint[];
2
2
  //# sourceMappingURL=entrypoints.d.ts.map
@@ -1 +1 @@
1
- {"version":3,"file":"entrypoints.d.ts","sourceRoot":"","sources":["../../src/auth/entrypoints.ts"],"names":[],"mappings":"AAIA,eAAO,MAAM,WAAW,OAAuB,CAAA"}
1
+ {"version":3,"file":"entrypoints.d.ts","sourceRoot":"","sources":["../../src/auth/entrypoints.ts"],"names":[],"mappings":"AAIA,eAAO,MAAM,WAAW,mDAAuB,CAAA"}
@@ -1 +1 @@
1
- {"version":3,"file":"component.js","sourceRoot":"","sources":["../../../../src/components/form/button/component.tsx"],"names":[],"mappings":"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"}
1
+ {"version":3,"file":"component.js","sourceRoot":"","sources":["../../../../src/components/form/button/component.tsx"],"names":[],"mappings":"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"}
@@ -1 +1 @@
1
- {"version":3,"file":"component.js","sourceRoot":"","sources":["../../../src/components/form/component.tsx"],"names":[],"mappings":"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"}
1
+ {"version":3,"file":"component.js","sourceRoot":"","sources":["../../../src/components/form/component.tsx"],"names":[],"mappings":";AACA,OAAO,EAAE,QAAQ,EAAE,WAAW,EAAE,OAAO,EAAE,MAAM,OAAO,CAAA;AACtD,OAAO,EAAE,YAAY,EAAE,OAAO,EAAE,MAAM,iBAAiB,CAAA;AACvD,OAAO,EAAE,WAAW,EAAE,MAAM,yBAAyB,CAAA;AACrD,OAAO,EAAE,WAAW,EAAE,mBAAmB,EAAE,MAAM,wBAAwB,CAAA;AAEzE,OAAO,GAAG,MAAM,KAAK,CAAA;AACrB,OAAO,aAAa,MAAM,aAAa,CAAA;AACvC,OAAO,EAAE,YAAY,EAAE,MAAM,uBAAuB,CAAA;AACpD,OAAO,EAAE,SAAS,EAAE,MAAM,kBAAkB,CAAA;AAC5C,OAAO,EAAE,eAAe,EAAE,MAAM,cAAc,CAAA;AAC9C,OAAO,EAAE,cAAc,EAAE,MAAM,iBAAiB,CAAA;AAChD,OAAO,EAAE,MAAM,EAAE,MAAM,cAAc,CAAA;AAErC,OAAO,EAAE,IAAI,EAAE,WAAW,EAAE,UAAU,EAAE,MAAM,sBAAsB,CAAA;AACpE,OAAO,EAAE,EAAE,EAAE,MAAM,aAAa,CAAA;AAEhC,MAAM,GAAG,GAAG,IAAI,GAAG,CAAC,EAAE,WAAW,EAAE,IAAI,EAAE,CAAC,CAAA;AAC1C,aAAa,CAAC,GAAG,CAAC,CAAA;AAElB,MAAM,CAAC,MAAM,IAAI,GAAqB,CAAC,KAAK,EAAE,EAAE;IAC9C,MAAM,EACJ,QAAQ,EAAE,QAAQ,EAAE,OAAO,EAAE,UAAU,EAAE,IAAI,EAAE,UAAU,EAAE,QAAQ,EACnE,QAAQ,EAAE,QAAQ,EAAE,IAAI,EAAE,SAAS,EAAE,KAAK,EAC3C,GAAG,KAAK,CAAA;IACT,MAAM,SAAS,GAAG,OAAO,CACvB,GAAG,EAAE,CAAC,QAAQ,IAAI,CAAC,UAAU,IAAI,IAAI,CAAC,CAAC,CAAC,mBAAmB,CAAC,UAAU,CAAC,CAAC,CAAC,CAAC,SAAS,CAAC,EACpF,CAAC,IAAI,EAAE,QAAQ,IAAI,IAAI,EAAE,UAAU,IAAI,IAAI,CAAC,CAC7C,CAAA;IAED,MAAM,MAAM,GAAG,SAAS,CAAC,KAAK,CAAC,CAAA;IAE/B,MAAM,IAAI,GAAG,OAAO,CAAC;QACnB,IAAI,EAAE,KAAK;QACX,aAAa,EAAE,SAAS;QACxB,QAAQ,EAAE,UAAU;YAClB,CAAC,CAAC,WAAW,CAAC,UAAqC,EAAE,EAAE,OAAO,EAAE,GAAG,CAAC,OAAO,EAAE,WAAW,EAAE,IAAI,EAAE,CAAC;YACjG,CAAC,CAAC,SAAS;QACb,UAAU,EAAE,GAAG;KAChB,CAAC,CAAA;IAEF,MAAM,MAAM,GAAG,WAAW,CAAC,CAAC,CAAC,IAAyB,EAAE,EAAE;QACxD,MAAM,MAAM,GAAG,UAAU,IAAI,IAAI;YAC/B,CAAC,CAAC,MAAM,CAAC,IAAI,CAAE,UAAkC,CAAC,UAAU,CAAC;YAC7D,CAAC,CAAC,MAAM,CAAC,IAAI,CAAC,IAAI,CAAC,CAAA;QACrB,MAAM,CAAC,OAAO,CAAC,GAAG,CAAC,EAAE;YACnB,IAAI,CAAC,QAAQ,CAAC,GAAG,EAAE,IAAI,CAAC,GAAG,CAAC,CAAC,CAAA;QAC/B,CAAC,CAAC,CAAA;IACJ,CAAC,CAAyB,EAAE,CAAC,IAAI,CAAC,CAAC,CAAA;IAEnC,MAAM,QAAQ,GAAG,WAAW,CAAC,CAAC,KAAc,EAAE,MAAM,GAAW,MAAM,EAAE,EAAE;QACvE,IAAI,CAAC,QAAQ,CAAC,MAAM,EAAE;YACpB,OAAO,EAAE,cAAc,CAAC,MAAM,CAC5B,KAAK,YAAY,KAAK,CAAC,CAAC,CAAC,KAAK,CAAC,CAAC,CAAC,GAAG,KAAK,EAAE,CAC5C,CAAC,OAAO,EAAE,CAAC,OAAO;SACpB,CAAC,CAAA;IACJ,CAAC,EAAE,CAAC,IAAI,CAAC,CAAC,CAAA;IAEV,IAAI,OAAO,IAAI,IAAI,EAAE,CAAC;QACpB,OAAO,CAAC,OAAO,GAAG,EAAE,IAAI,EAAE,MAAM,EAAE,MAAM,EAAE,KAAK,EAAE,QAAQ,EAAE,CAAA;IAC7D,CAAC;IAED,MAAM,OAAO,GAAG,OAAO,CAAC,GAAG,EAAE,CAAC,eAAe,CAAC,UAAU,EAAE,QAAQ,CAAC,EAAE,CAAC,UAAU,EAAE,QAAQ,CAAC,CAAC,CAAA;IAE5F,MAAM,OAAO,GAAG,GAAG,EAAE,CAAC,CACpB,cAAK,SAAS,EAAE,EAAE,CAAC,iDAAiD,EAAE,CAAC,QAAQ,IAAI,OAAO,EAAE,CAAC,QAAQ,IAAI,SAAS,CAAC,EAAE,KAAK,EAAE,CAAC,QAAQ,CAAC,CAAC,CAAC,KAAK,CAAC,CAAC,CAAC,SAAS,YACtJ,KAAK,CAAC,OAAO,CAAC,QAAQ,CAAC;YACtB,CAAC,CAAC,QAAQ,CAAC,GAAG,CAAC,QAAQ,EAAE,CAAC,KAAK,EAAE,KAAK,EAAE,EAAE,CAAC,wBAAkB,KAAK,IAAb,KAAK,CAAe,CAAC;YAC1E,CAAC,CAAC,QAAQ,GAER,CACP,CAAA;IAED,IAAI,QAAQ,KAAK,IAAI,EAAE,CAAC;QACtB,MAAM,IAAI,GAAG,IAAI,CAAC,aAAa,CAAC,MAAM,CAAC,CAAA;QACvC,OAAO,KAAC,YAAY,OAAK,IAAI,YAC3B,KAAC,WAAW,OAAK,KAAK,EAAE,MAAM,EAAE,MAAM,YACpC,MAAC,IAAI,IAAC,SAAS,EAAE,EAAE,CAAC,OAAO,EAAE,+BAA+B,EAAE,SAAS,CAAC,EAAE,KAAK,EAAE,KAAK,aACpF,MAAC,WAAW,eACT,OAAO,EAAE,EACT,IAAI,CAAC,OAAO,IAAI,IAAI,CAAC,KAAK,EAAE,OAAO;oCAClC,cAAK,SAAS,EAAC,MAAM,YACnB,KAAC,MAAM,IAAC,EAAE,EAAE,KAAK,EAAE,IAAI,EAAE,IAAI,EAAE,KAAK,EAAE,cAAc,CAAC,MAAM,CAAC,IAAI,CAAC,KAAK,CAAC,OAAO,CAAC,GAAI,GAC/E,IAEI,EACb,QAAQ,IAAI,IAAI,IAAI,CACnB,KAAC,UAAU,IAAC,SAAS,EAAC,2CAA2C,YAC/D,KAAC,YAAY,IAAC,MAAM,EAAE,MAAM,EAAE,QAAQ,EAAE,KAAK,EAAC,IAAI,EAAC,EAAE,CAAC,QAAQ,CAAC,IAAI,EAAE,MAAM,CAAC,GAAI,GACrE,CACd,IACI,GACK,GACD,CAAA;IACjB,CAAC;IAED,OAAO,KAAC,YAAY,OAAK,IAAI,YAC3B,KAAC,WAAW,OAAK,KAAK,EAAE,MAAM,EAAE,MAAM,YAAG,OAAO,EAAE,GAAe,GACpD,CAAA;AACjB,CAAC,CAAA"}
@@ -1 +1 @@
1
- {"version":3,"file":"helper.d.ts","sourceRoot":"","sources":["../../src/components/helper.ts"],"names":[],"mappings":"AACA,OAAO,EAAE,YAAY,EAAE,MAAM,wBAAwB,CAAA;AAErD;;;;;;;;;GASG;AACH,eAAO,MAAM,eAAe,GAC1B,aAAa,YAAY,EACzB,WAAW,YAAY,KACtB,MA4BF,CAAA;AAwBD,eAAO,MAAM,aAAa,QAAO,MAchC,CAAA;AAED,eAAO,MAAM,gBAAgB,GAAI,CAAC,EAAE,KAAK,MAAM,CAAC,MAAM,EAAE,CAAC,CAAC,EAAE,MAAM,CAAC,EAAE,aAAa,MAAM,KAAG,CAQ1F,CAAA"}
1
+ {"version":3,"file":"helper.d.ts","sourceRoot":"","sources":["../../src/components/helper.ts"],"names":[],"mappings":"AACA,OAAO,EAAE,YAAY,EAAE,MAAM,wBAAwB,CAAA;AAErD;;;;;;;;;GASG;AACH,eAAO,MAAM,eAAe,gBACb,YAAY,aACd,YAAY,KACtB,MA4BF,CAAA;AAwBD,eAAO,MAAM,aAAa,QAAO,MAchC,CAAA;AAED,eAAO,MAAM,gBAAgB,GAAI,CAAC,OAAO,MAAM,CAAC,MAAM,EAAE,CAAC,CAAC,QAAQ,CAAC,eAAe,MAAM,KAAG,CAQ1F,CAAA"}
@@ -1 +1 @@
1
- {"version":3,"file":"append.d.ts","sourceRoot":"","sources":["../../../src/components/login/append.ts"],"names":[],"mappings":"AAAA,OAAO,KAAK,EAAE,aAAa,EAAE,SAAS,EAAE,MAAM,OAAO,CAAA;AAErD,OAAO,KAAK,EAAE,gBAAgB,EAAE,MAAM,6BAA6B,CAAA;AACnE,OAAO,KAAK,EAAE,WAAW,EAAE,YAAY,EAAE,MAAM,mBAAmB,CAAA;AAGlE,MAAM,WAAW,gBAAiB,SAAQ,IAAI,CAAC,gBAAgB,EAAE,WAAW,CAAC;IAC3E,0DAA0D;IAC1D,IAAI,CAAC,EAAE,aAAa,CAAC;QAAE,SAAS,CAAC,EAAE,MAAM,CAAA;KAAE,CAAC,GAAG,SAAS,CAAA;CACzD;AAED;;;;;;;;;;GAUG;AACH,eAAO,MAAM,iBAAiB,GAAI,CAAC,SAAS,WAAW,EAAE,CAAC,SAAS,YAAY,CAAC,CAAC,CAAC,EAChF,KAAK,CAAC,EAAE,QAAQ,gBAAgB,KAC/B,CASF,CAAA"}
1
+ {"version":3,"file":"append.d.ts","sourceRoot":"","sources":["../../../src/components/login/append.ts"],"names":[],"mappings":"AAAA,OAAO,KAAK,EAAE,aAAa,EAAE,SAAS,EAAE,MAAM,OAAO,CAAA;AAErD,OAAO,KAAK,EAAE,gBAAgB,EAAE,MAAM,6BAA6B,CAAA;AACnE,OAAO,KAAK,EAAE,WAAW,EAAE,YAAY,EAAE,MAAM,mBAAmB,CAAA;AAGlE,MAAM,WAAW,gBAAiB,SAAQ,IAAI,CAAC,gBAAgB,EAAE,WAAW,CAAC;IAC3E,0DAA0D;IAC1D,IAAI,CAAC,EAAE,aAAa,CAAC;QAAE,SAAS,CAAC,EAAE,MAAM,CAAA;KAAE,CAAC,GAAG,SAAS,CAAA;CACzD;AAED;;;;;;;;;;GAUG;AACH,eAAO,MAAM,iBAAiB,GAAI,CAAC,SAAS,WAAW,EAAE,CAAC,SAAS,YAAY,CAAC,CAAC,CAAC,OAC3E,CAAC,UAAU,gBAAgB,KAC/B,CASF,CAAA"}
@@ -1 +1 @@
1
- {"version":3,"file":"context.d.ts","sourceRoot":"","sources":["../src/context.ts"],"names":[],"mappings":"AACA,OAAO,KAAK,EAAE,SAAS,EAAG,UAAU,EAAE,MAAM,YAAY,CAAA;AAKxD,eAAO,MAAM,WAAW,GAAI,CAAC,SAAS,SAAS,EAAE,CAAC,SAAS,UAAU,CAAC,CAAC,CAAC,EAAE,KAAK,CAAC,KAAG,CAalF,CAAA;AAED,eAAO,MAAM,UAAU,GAAI,CAAC,SAAS,SAAS,GAAG,SAAS,EAAC,CAAC,SAAS,UAAU,CAAC,CAAC,CAAC,GAAG,UAAU,CAAC,CAAC,CAAC,QACnF,CAAA"}
1
+ {"version":3,"file":"context.d.ts","sourceRoot":"","sources":["../src/context.ts"],"names":[],"mappings":"AACA,OAAO,KAAK,EAAE,SAAS,EAAG,UAAU,EAAE,MAAM,YAAY,CAAA;AAKxD,eAAO,MAAM,WAAW,GAAI,CAAC,SAAS,SAAS,EAAE,CAAC,SAAS,UAAU,CAAC,CAAC,CAAC,OAAO,CAAC,KAAG,CAalF,CAAA;AAED,eAAO,MAAM,UAAU,GAAI,CAAC,SAAS,SAAS,GAAG,SAAS,EAAC,CAAC,SAAS,UAAU,CAAC,CAAC,CAAC,GAAG,UAAU,CAAC,CAAC,CAAC,QACnF,CAAA"}
@@ -1,2 +1,2 @@
1
- export declare const entrypoints: any[];
1
+ export declare const entrypoints: import("@owlmeans/entrypoint").CommonEntrypoint[];
2
2
  //# sourceMappingURL=entrypoints.d.ts.map
@@ -1 +1 @@
1
- {"version":3,"file":"entrypoints.d.ts","sourceRoot":"","sources":["../src/entrypoints.ts"],"names":[],"mappings":"AAIA,eAAO,MAAM,WAAW,OAAuB,CAAA"}
1
+ {"version":3,"file":"entrypoints.d.ts","sourceRoot":"","sources":["../src/entrypoints.ts"],"names":[],"mappings":"AAIA,eAAO,MAAM,WAAW,mDAAuB,CAAA"}
@@ -0,0 +1,2 @@
1
+ export * from './use-mobile.js';
2
+ //# sourceMappingURL=index.d.ts.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"index.d.ts","sourceRoot":"","sources":["../../src/hooks/index.ts"],"names":[],"mappings":"AAAA,cAAc,iBAAiB,CAAA"}
@@ -0,0 +1,2 @@
1
+ export * from './use-mobile.js';
2
+ //# sourceMappingURL=index.js.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"index.js","sourceRoot":"","sources":["../../src/hooks/index.ts"],"names":[],"mappings":"AAAA,cAAc,iBAAiB,CAAA"}
@@ -0,0 +1,16 @@
1
+ /** Tailwind's `md` — the width at which the navigation shell swaps its side menu for the bar. */
2
+ export declare const MOBILE_BREAKPOINT = 768;
3
+ /**
4
+ * Whether the viewport is narrower than Tailwind's `md`, for a component that has to pick a tree
5
+ * rather than render both and hide one with `md:hidden`.
6
+ *
7
+ * It matches a media query instead of listening for `resize` the way `useBreakPoint` does: the
8
+ * browser evaluates the query itself and notifies only when the answer flips, so dragging a window
9
+ * across the whole width costs one render rather than one per frame.
10
+ *
11
+ * The answer is `false` before the first effect and on a server render, because `window` is the
12
+ * only thing that knows the width. That makes the desktop tree the one server-rendered HTML and
13
+ * the first client paint agree on, so hydration never mismatches.
14
+ */
15
+ export declare const useIsMobile: () => boolean;
16
+ //# sourceMappingURL=use-mobile.d.ts.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"use-mobile.d.ts","sourceRoot":"","sources":["../../src/hooks/use-mobile.ts"],"names":[],"mappings":"AAEA,iGAAiG;AACjG,eAAO,MAAM,iBAAiB,MAAM,CAAA;AAEpC;;;;;;;;;;;GAWG;AACH,eAAO,MAAM,WAAW,QAAO,OAiB9B,CAAA"}
@@ -0,0 +1,30 @@
1
+ import { useEffect, useState } from 'react';
2
+ /** Tailwind's `md` — the width at which the navigation shell swaps its side menu for the bar. */
3
+ export const MOBILE_BREAKPOINT = 768;
4
+ /**
5
+ * Whether the viewport is narrower than Tailwind's `md`, for a component that has to pick a tree
6
+ * rather than render both and hide one with `md:hidden`.
7
+ *
8
+ * It matches a media query instead of listening for `resize` the way `useBreakPoint` does: the
9
+ * browser evaluates the query itself and notifies only when the answer flips, so dragging a window
10
+ * across the whole width costs one render rather than one per frame.
11
+ *
12
+ * The answer is `false` before the first effect and on a server render, because `window` is the
13
+ * only thing that knows the width. That makes the desktop tree the one server-rendered HTML and
14
+ * the first client paint agree on, so hydration never mismatches.
15
+ */
16
+ export const useIsMobile = () => {
17
+ const [isMobile, setIsMobile] = useState(false);
18
+ useEffect(() => {
19
+ if (typeof window === 'undefined' || window.matchMedia == null) {
20
+ return;
21
+ }
22
+ const query = window.matchMedia(`(max-width: ${MOBILE_BREAKPOINT - 1}px)`);
23
+ const read = () => setIsMobile(query.matches);
24
+ read();
25
+ query.addEventListener('change', read);
26
+ return () => query.removeEventListener('change', read);
27
+ }, []);
28
+ return isMobile;
29
+ };
30
+ //# sourceMappingURL=use-mobile.js.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"use-mobile.js","sourceRoot":"","sources":["../../src/hooks/use-mobile.ts"],"names":[],"mappings":"AAAA,OAAO,EAAE,SAAS,EAAE,QAAQ,EAAE,MAAM,OAAO,CAAA;AAE3C,iGAAiG;AACjG,MAAM,CAAC,MAAM,iBAAiB,GAAG,GAAG,CAAA;AAEpC;;;;;;;;;;;GAWG;AACH,MAAM,CAAC,MAAM,WAAW,GAAG,GAAY,EAAE;IACvC,MAAM,CAAC,QAAQ,EAAE,WAAW,CAAC,GAAG,QAAQ,CAAC,KAAK,CAAC,CAAA;IAE/C,SAAS,CAAC,GAAG,EAAE;QACb,IAAI,OAAO,MAAM,KAAK,WAAW,IAAI,MAAM,CAAC,UAAU,IAAI,IAAI,EAAE,CAAC;YAC/D,OAAM;QACR,CAAC;QAED,MAAM,KAAK,GAAG,MAAM,CAAC,UAAU,CAAC,eAAe,iBAAiB,GAAG,CAAC,KAAK,CAAC,CAAA;QAC1E,MAAM,IAAI,GAAG,GAAG,EAAE,CAAC,WAAW,CAAC,KAAK,CAAC,OAAO,CAAC,CAAA;QAC7C,IAAI,EAAE,CAAA;QACN,KAAK,CAAC,gBAAgB,CAAC,QAAQ,EAAE,IAAI,CAAC,CAAA;QAEtC,OAAO,GAAG,EAAE,CAAC,KAAK,CAAC,mBAAmB,CAAC,QAAQ,EAAE,IAAI,CAAC,CAAA;IACxD,CAAC,EAAE,EAAE,CAAC,CAAA;IAEN,OAAO,QAAQ,CAAA;AACjB,CAAC,CAAA"}
package/build/index.d.ts CHANGED
@@ -4,5 +4,7 @@ export * from './exports.js';
4
4
  export * from './context.js';
5
5
  export * from './entrypoints.js';
6
6
  export * from './components/index.js';
7
+ export * from './hooks/index.js';
8
+ export * from './utils.js';
7
9
  export * from '@owlmeans/client-panel';
8
10
  //# sourceMappingURL=index.d.ts.map
@@ -1 +1 @@
1
- {"version":3,"file":"index.d.ts","sourceRoot":"","sources":["../src/index.ts"],"names":[],"mappings":"AACA,mBAAmB,YAAY,CAAA;AAC/B,cAAc,WAAW,CAAA;AACzB,cAAc,cAAc,CAAA;AAC5B,cAAc,cAAc,CAAA;AAC5B,cAAc,kBAAkB,CAAA;AAChC,cAAc,uBAAuB,CAAA;AAErC,cAAc,wBAAwB,CAAA"}
1
+ {"version":3,"file":"index.d.ts","sourceRoot":"","sources":["../src/index.ts"],"names":[],"mappings":"AACA,mBAAmB,YAAY,CAAA;AAC/B,cAAc,WAAW,CAAA;AACzB,cAAc,cAAc,CAAA;AAC5B,cAAc,cAAc,CAAA;AAC5B,cAAc,kBAAkB,CAAA;AAChC,cAAc,uBAAuB,CAAA;AACrC,cAAc,kBAAkB,CAAA;AAChC,cAAc,YAAY,CAAA;AAE1B,cAAc,wBAAwB,CAAA"}
package/build/index.js CHANGED
@@ -3,5 +3,7 @@ export * from './exports.js';
3
3
  export * from './context.js';
4
4
  export * from './entrypoints.js';
5
5
  export * from './components/index.js';
6
+ export * from './hooks/index.js';
7
+ export * from './utils.js';
6
8
  export * from '@owlmeans/client-panel';
7
9
  //# sourceMappingURL=index.js.map
@@ -1 +1 @@
1
- {"version":3,"file":"index.js","sourceRoot":"","sources":["../src/index.ts"],"names":[],"mappings":"AAEA,cAAc,WAAW,CAAA;AACzB,cAAc,cAAc,CAAA;AAC5B,cAAc,cAAc,CAAA;AAC5B,cAAc,kBAAkB,CAAA;AAChC,cAAc,uBAAuB,CAAA;AAErC,cAAc,wBAAwB,CAAA"}
1
+ {"version":3,"file":"index.js","sourceRoot":"","sources":["../src/index.ts"],"names":[],"mappings":"AAEA,cAAc,WAAW,CAAA;AACzB,cAAc,cAAc,CAAA;AAC5B,cAAc,cAAc,CAAA;AAC5B,cAAc,kBAAkB,CAAA;AAChC,cAAc,uBAAuB,CAAA;AACrC,cAAc,kBAAkB,CAAA;AAChC,cAAc,YAAY,CAAA;AAE1B,cAAc,wBAAwB,CAAA"}
@@ -0,0 +1,19 @@
1
+ import type { FC } from 'react';
2
+ import type { JobRecord } from '@owlmeans/queue';
3
+ import type { JobProps, JobStatusProps } from './types.js';
4
+ /**
5
+ * A job's progress as a percentage, or `undefined` when there is nothing to show yet.
6
+ *
7
+ * `JobRecord.progress` is deliberately `unknown` — a processor reports whatever it counts — so the
8
+ * three shapes worth understanding are read here and everything else falls through to the
9
+ * indeterminate bar, which is the honest answer for "running, no idea how far".
10
+ */
11
+ export declare const jobProgressValue: (job: JobRecord) => number | undefined;
12
+ /**
13
+ * The bar for one job. A job with nothing to report animates indeterminately rather than sitting
14
+ * at zero, because zero and "the processor never called `progress()`" look identical otherwise.
15
+ */
16
+ export declare const JobProgress: FC<JobProps>;
17
+ /** The state pill. `data-state` carries the raw state, so a test never keys on the wording. */
18
+ export declare const JobStatus: FC<JobStatusProps>;
19
+ //# sourceMappingURL=component.d.ts.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"component.d.ts","sourceRoot":"","sources":["../../src/jobs/component.tsx"],"names":[],"mappings":"AAAA,OAAO,KAAK,EAAE,EAAE,EAAE,MAAM,OAAO,CAAA;AAG/B,OAAO,KAAK,EAAE,SAAS,EAAE,MAAM,iBAAiB,CAAA;AAGhD,OAAO,KAAK,EAAE,QAAQ,EAAE,cAAc,EAAE,MAAM,YAAY,CAAA;AAE1D;;;;;;GAMG;AACH,eAAO,MAAM,gBAAgB,QAAS,SAAS,KAAG,MAAM,GAAG,SAW1D,CAAA;AAcD;;;GAGG;AACH,eAAO,MAAM,WAAW,EAAE,EAAE,CAAC,QAAQ,CASpC,CAAA;AAWD,+FAA+F;AAC/F,eAAO,MAAM,SAAS,EAAE,EAAE,CAAC,cAAc,CAYxC,CAAA"}
@@ -0,0 +1,55 @@
1
+ import { jsx as _jsx } from "react/jsx-runtime";
2
+ import { useMemo } from 'react';
3
+ import { JobState } from '@owlmeans/queue';
4
+ import { Progress } from '@/components/ui/progress';
5
+ import { cn } from '@/lib/utils';
6
+ /**
7
+ * A job's progress as a percentage, or `undefined` when there is nothing to show yet.
8
+ *
9
+ * `JobRecord.progress` is deliberately `unknown` — a processor reports whatever it counts — so the
10
+ * three shapes worth understanding are read here and everything else falls through to the
11
+ * indeterminate bar, which is the honest answer for "running, no idea how far".
12
+ */
13
+ export const jobProgressValue = (job) => {
14
+ if (job.state === JobState.Completed) {
15
+ return 100;
16
+ }
17
+ const progress = job.progress;
18
+ const value = typeof progress === 'number' ? progress
19
+ : typeof progress === 'object' && progress != null
20
+ ? percentOf(progress)
21
+ : undefined;
22
+ return value == null ? undefined : Math.max(0, Math.min(100, value));
23
+ };
24
+ const percentOf = (progress) => {
25
+ if (typeof progress.percent === 'number') {
26
+ return progress.percent;
27
+ }
28
+ const { done, total } = progress;
29
+ if (typeof done === 'number' && typeof total === 'number' && total > 0) {
30
+ return (done / total) * 100;
31
+ }
32
+ return undefined;
33
+ };
34
+ /**
35
+ * The bar for one job. A job with nothing to report animates indeterminately rather than sitting
36
+ * at zero, because zero and "the processor never called `progress()`" look identical otherwise.
37
+ */
38
+ export const JobProgress = ({ job, className, style }) => {
39
+ const value = useMemo(() => jobProgressValue(job), [job.state, job.progress]);
40
+ return _jsx(Progress, { "data-slot": "job-progress", value: value, className: cn('w-full', className), style: style });
41
+ };
42
+ const STATE_STYLE = {
43
+ [JobState.Waiting]: 'border-border bg-muted text-muted-foreground',
44
+ [JobState.Delayed]: 'border-border bg-muted text-muted-foreground',
45
+ [JobState.Active]: 'border-border bg-accent text-accent-foreground',
46
+ [JobState.Completed]: 'border-primary/40 bg-primary/10 text-primary',
47
+ [JobState.Failed]: 'border-destructive/40 bg-destructive/10 text-destructive',
48
+ [JobState.Unknown]: 'border-border bg-muted text-muted-foreground',
49
+ };
50
+ /** The state pill. `data-state` carries the raw state, so a test never keys on the wording. */
51
+ export const JobStatus = ({ job, labels, className, style }) => {
52
+ const state = job.state ?? JobState.Unknown;
53
+ return _jsx("span", { "data-slot": "job-status", "data-state": state, className: cn('inline-flex items-center rounded-full border px-2 py-0.5 text-xs font-medium', STATE_STYLE[state], className), style: style, children: labels?.[state] ?? state });
54
+ };
55
+ //# sourceMappingURL=component.js.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"component.js","sourceRoot":"","sources":["../../src/jobs/component.tsx"],"names":[],"mappings":";AACA,OAAO,EAAE,OAAO,EAAE,MAAM,OAAO,CAAA;AAC/B,OAAO,EAAE,QAAQ,EAAE,MAAM,iBAAiB,CAAA;AAE1C,OAAO,EAAE,QAAQ,EAAE,MAAM,0BAA0B,CAAA;AACnD,OAAO,EAAE,EAAE,EAAE,MAAM,aAAa,CAAA;AAGhC;;;;;;GAMG;AACH,MAAM,CAAC,MAAM,gBAAgB,GAAG,CAAC,GAAc,EAAsB,EAAE;IACrE,IAAI,GAAG,CAAC,KAAK,KAAK,QAAQ,CAAC,SAAS,EAAE,CAAC;QACrC,OAAO,GAAG,CAAA;IACZ,CAAC;IACD,MAAM,QAAQ,GAAG,GAAG,CAAC,QAAQ,CAAA;IAC7B,MAAM,KAAK,GAAG,OAAO,QAAQ,KAAK,QAAQ,CAAC,CAAC,CAAC,QAAQ;QACnD,CAAC,CAAC,OAAO,QAAQ,KAAK,QAAQ,IAAI,QAAQ,IAAI,IAAI;YAChD,CAAC,CAAC,SAAS,CAAC,QAAmC,CAAC;YAChD,CAAC,CAAC,SAAS,CAAA;IAEf,OAAO,KAAK,IAAI,IAAI,CAAC,CAAC,CAAC,SAAS,CAAC,CAAC,CAAC,IAAI,CAAC,GAAG,CAAC,CAAC,EAAE,IAAI,CAAC,GAAG,CAAC,GAAG,EAAE,KAAK,CAAC,CAAC,CAAA;AACtE,CAAC,CAAA;AAED,MAAM,SAAS,GAAG,CAAC,QAAiC,EAAsB,EAAE;IAC1E,IAAI,OAAO,QAAQ,CAAC,OAAO,KAAK,QAAQ,EAAE,CAAC;QACzC,OAAO,QAAQ,CAAC,OAAO,CAAA;IACzB,CAAC;IACD,MAAM,EAAE,IAAI,EAAE,KAAK,EAAE,GAAG,QAAQ,CAAA;IAChC,IAAI,OAAO,IAAI,KAAK,QAAQ,IAAI,OAAO,KAAK,KAAK,QAAQ,IAAI,KAAK,GAAG,CAAC,EAAE,CAAC;QACvE,OAAO,CAAC,IAAI,GAAG,KAAK,CAAC,GAAG,GAAG,CAAA;IAC7B,CAAC;IAED,OAAO,SAAS,CAAA;AAClB,CAAC,CAAA;AAED;;;GAGG;AACH,MAAM,CAAC,MAAM,WAAW,GAAiB,CAAC,EAAE,GAAG,EAAE,SAAS,EAAE,KAAK,EAAE,EAAE,EAAE;IACrE,MAAM,KAAK,GAAG,OAAO,CAAC,GAAG,EAAE,CAAC,gBAAgB,CAAC,GAAG,CAAC,EAAE,CAAC,GAAG,CAAC,KAAK,EAAE,GAAG,CAAC,QAAQ,CAAC,CAAC,CAAA;IAE7E,OAAO,KAAC,QAAQ,iBACJ,cAAc,EACxB,KAAK,EAAE,KAAK,EACZ,SAAS,EAAE,EAAE,CAAC,QAAQ,EAAE,SAAS,CAAC,EAClC,KAAK,EAAE,KAAK,GACZ,CAAA;AACJ,CAAC,CAAA;AAED,MAAM,WAAW,GAA6B;IAC5C,CAAC,QAAQ,CAAC,OAAO,CAAC,EAAE,8CAA8C;IAClE,CAAC,QAAQ,CAAC,OAAO,CAAC,EAAE,8CAA8C;IAClE,CAAC,QAAQ,CAAC,MAAM,CAAC,EAAE,gDAAgD;IACnE,CAAC,QAAQ,CAAC,SAAS,CAAC,EAAE,8CAA8C;IACpE,CAAC,QAAQ,CAAC,MAAM,CAAC,EAAE,0DAA0D;IAC7E,CAAC,QAAQ,CAAC,OAAO,CAAC,EAAE,8CAA8C;CACnE,CAAA;AAED,+FAA+F;AAC/F,MAAM,CAAC,MAAM,SAAS,GAAuB,CAAC,EAAE,GAAG,EAAE,MAAM,EAAE,SAAS,EAAE,KAAK,EAAE,EAAE,EAAE;IACjF,MAAM,KAAK,GAAG,GAAG,CAAC,KAAK,IAAI,QAAQ,CAAC,OAAO,CAAA;IAE3C,OAAO,4BACK,YAAY,gBACV,KAAK,EACjB,SAAS,EAAE,EAAE,CACX,8EAA8E,EAC9E,WAAW,CAAC,KAAK,CAAC,EAAE,SAAS,CAC9B,EACD,KAAK,EAAE,KAAK,YACZ,MAAM,EAAE,CAAC,KAAK,CAAC,IAAI,KAAK,GAAQ,CAAA;AACpC,CAAC,CAAA"}
@@ -0,0 +1,4 @@
1
+ export type * from './types.js';
2
+ export * from './component.js';
3
+ export * from './toasts.js';
4
+ //# sourceMappingURL=index.d.ts.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"index.d.ts","sourceRoot":"","sources":["../../src/jobs/index.ts"],"names":[],"mappings":"AAAA,mBAAmB,YAAY,CAAA;AAE/B,cAAc,gBAAgB,CAAA;AAC9B,cAAc,aAAa,CAAA"}
@@ -0,0 +1,3 @@
1
+ export * from './component.js';
2
+ export * from './toasts.js';
3
+ //# sourceMappingURL=index.js.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"index.js","sourceRoot":"","sources":["../../src/jobs/index.ts"],"names":[],"mappings":"AAEA,cAAc,gBAAgB,CAAA;AAC9B,cAAc,aAAa,CAAA"}
@@ -0,0 +1,14 @@
1
+ import type { JobRecord } from '@owlmeans/queue';
2
+ import type { JobToastOptions } from './types.js';
3
+ /**
4
+ * Announce jobs as they finish, on the `Toaster` the layout already mounts.
5
+ *
6
+ * Hand it whatever the screen is already showing — `useJobs()` from `@owlmeans/client-job` maps
7
+ * straight onto it — and it raises one toast per job the first time that job settles.
8
+ *
9
+ * **The first pass never toasts.** A screen opening onto a store seeded with yesterday's finished
10
+ * jobs would otherwise fire a stack of them at once, so everything already settled when this
11
+ * mounts is recorded as announced and only what settles afterwards is reported.
12
+ */
13
+ export declare const useJobToasts: (jobs: JobRecord[], opts?: JobToastOptions) => void;
14
+ //# sourceMappingURL=toasts.d.ts.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"toasts.d.ts","sourceRoot":"","sources":["../../src/jobs/toasts.ts"],"names":[],"mappings":"AAGA,OAAO,KAAK,EAAE,SAAS,EAAE,MAAM,iBAAiB,CAAA;AAChD,OAAO,KAAK,EAAE,eAAe,EAAE,MAAM,YAAY,CAAA;AAEjD;;;;;;;;;GASG;AACH,eAAO,MAAM,YAAY,SAAU,SAAS,EAAE,SAAS,eAAe,KAAG,IAwBxE,CAAA"}
@@ -0,0 +1,39 @@
1
+ import { useEffect, useRef } from 'react';
2
+ import { toast } from 'sonner';
3
+ import { isSettled, JobState } from '@owlmeans/queue';
4
+ /**
5
+ * Announce jobs as they finish, on the `Toaster` the layout already mounts.
6
+ *
7
+ * Hand it whatever the screen is already showing — `useJobs()` from `@owlmeans/client-job` maps
8
+ * straight onto it — and it raises one toast per job the first time that job settles.
9
+ *
10
+ * **The first pass never toasts.** A screen opening onto a store seeded with yesterday's finished
11
+ * jobs would otherwise fire a stack of them at once, so everything already settled when this
12
+ * mounts is recorded as announced and only what settles afterwards is reported.
13
+ */
14
+ export const useJobToasts = (jobs, opts) => {
15
+ const announced = useRef(new Set());
16
+ const primed = useRef(false);
17
+ // Re-run on what actually decides a toast, not on the array identity a caller rebuilds per render.
18
+ const settlement = jobs.map(job => `${job.id}:${job.state}`).join(',');
19
+ useEffect(() => {
20
+ jobs.forEach(job => {
21
+ if (job.id == null || !isSettled(job.state) || announced.current.has(job.id)) {
22
+ return;
23
+ }
24
+ announced.current.add(job.id);
25
+ if (!primed.current) {
26
+ return;
27
+ }
28
+ const message = opts?.message?.(job) ?? job.name;
29
+ if (job.state === JobState.Completed) {
30
+ toast.success(message);
31
+ }
32
+ else {
33
+ toast.error(job.error != null && job.error !== '' ? `${String(message)}: ${job.error}` : message);
34
+ }
35
+ });
36
+ primed.current = true;
37
+ }, [settlement]);
38
+ };
39
+ //# sourceMappingURL=toasts.js.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"toasts.js","sourceRoot":"","sources":["../../src/jobs/toasts.ts"],"names":[],"mappings":"AAAA,OAAO,EAAE,SAAS,EAAE,MAAM,EAAE,MAAM,OAAO,CAAA;AACzC,OAAO,EAAE,KAAK,EAAE,MAAM,QAAQ,CAAA;AAC9B,OAAO,EAAE,SAAS,EAAE,QAAQ,EAAE,MAAM,iBAAiB,CAAA;AAIrD;;;;;;;;;GASG;AACH,MAAM,CAAC,MAAM,YAAY,GAAG,CAAC,IAAiB,EAAE,IAAsB,EAAQ,EAAE;IAC9E,MAAM,SAAS,GAAG,MAAM,CAAc,IAAI,GAAG,EAAE,CAAC,CAAA;IAChD,MAAM,MAAM,GAAG,MAAM,CAAC,KAAK,CAAC,CAAA;IAC5B,mGAAmG;IACnG,MAAM,UAAU,GAAG,IAAI,CAAC,GAAG,CAAC,GAAG,CAAC,EAAE,CAAC,GAAG,GAAG,CAAC,EAAE,IAAI,GAAG,CAAC,KAAK,EAAE,CAAC,CAAC,IAAI,CAAC,GAAG,CAAC,CAAA;IAEtE,SAAS,CAAC,GAAG,EAAE;QACb,IAAI,CAAC,OAAO,CAAC,GAAG,CAAC,EAAE;YACjB,IAAI,GAAG,CAAC,EAAE,IAAI,IAAI,IAAI,CAAC,SAAS,CAAC,GAAG,CAAC,KAAK,CAAC,IAAI,SAAS,CAAC,OAAO,CAAC,GAAG,CAAC,GAAG,CAAC,EAAE,CAAC,EAAE,CAAC;gBAC7E,OAAM;YACR,CAAC;YACD,SAAS,CAAC,OAAO,CAAC,GAAG,CAAC,GAAG,CAAC,EAAE,CAAC,CAAA;YAC7B,IAAI,CAAC,MAAM,CAAC,OAAO,EAAE,CAAC;gBACpB,OAAM;YACR,CAAC;YACD,MAAM,OAAO,GAAG,IAAI,EAAE,OAAO,EAAE,CAAC,GAAG,CAAC,IAAI,GAAG,CAAC,IAAI,CAAA;YAChD,IAAI,GAAG,CAAC,KAAK,KAAK,QAAQ,CAAC,SAAS,EAAE,CAAC;gBACrC,KAAK,CAAC,OAAO,CAAC,OAAO,CAAC,CAAA;YACxB,CAAC;iBAAM,CAAC;gBACN,KAAK,CAAC,KAAK,CAAC,GAAG,CAAC,KAAK,IAAI,IAAI,IAAI,GAAG,CAAC,KAAK,KAAK,EAAE,CAAC,CAAC,CAAC,GAAG,MAAM,CAAC,OAAO,CAAC,KAAK,GAAG,CAAC,KAAK,EAAE,CAAC,CAAC,CAAC,OAAO,CAAC,CAAA;YACnG,CAAC;QACH,CAAC,CAAC,CAAA;QACF,MAAM,CAAC,OAAO,GAAG,IAAI,CAAA;IACvB,CAAC,EAAE,CAAC,UAAU,CAAC,CAAC,CAAA;AAClB,CAAC,CAAA"}
@@ -0,0 +1,21 @@
1
+ import type { ReactNode } from 'react';
2
+ import type { JobRecord, JobState } from '@owlmeans/queue';
3
+ import type { StyledProps } from '../components/types.js';
4
+ export interface JobProps extends StyledProps {
5
+ job: JobRecord;
6
+ }
7
+ export interface JobStatusProps extends JobProps {
8
+ /**
9
+ * What each state is called on screen.
10
+ *
11
+ * There is no packaged wording: the states are broker vocabulary, and the sentence an app wants
12
+ * for them ("Queued", "Rendering", "Ready") is the app's own copy in the app's own namespace.
13
+ * Absent a label the raw state is rendered, which is data rather than an untranslated string.
14
+ */
15
+ labels?: Partial<Record<JobState, ReactNode>>;
16
+ }
17
+ export interface JobToastOptions {
18
+ /** What the toast says. The job's own name when omitted. */
19
+ message?: (job: JobRecord) => ReactNode;
20
+ }
21
+ //# sourceMappingURL=types.d.ts.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"types.d.ts","sourceRoot":"","sources":["../../src/jobs/types.ts"],"names":[],"mappings":"AAAA,OAAO,KAAK,EAAE,SAAS,EAAE,MAAM,OAAO,CAAA;AACtC,OAAO,KAAK,EAAE,SAAS,EAAE,QAAQ,EAAE,MAAM,iBAAiB,CAAA;AAC1D,OAAO,KAAK,EAAE,WAAW,EAAE,MAAM,wBAAwB,CAAA;AAEzD,MAAM,WAAW,QAAS,SAAQ,WAAW;IAC3C,GAAG,EAAE,SAAS,CAAA;CACf;AAED,MAAM,WAAW,cAAe,SAAQ,QAAQ;IAC9C;;;;;;OAMG;IACH,MAAM,CAAC,EAAE,OAAO,CAAC,MAAM,CAAC,QAAQ,EAAE,SAAS,CAAC,CAAC,CAAA;CAC9C;AAED,MAAM,WAAW,eAAe;IAC9B,4DAA4D;IAC5D,OAAO,CAAC,EAAE,CAAC,GAAG,EAAE,SAAS,KAAK,SAAS,CAAA;CACxC"}
@@ -0,0 +1,2 @@
1
+ export {};
2
+ //# sourceMappingURL=types.js.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"types.js","sourceRoot":"","sources":["../../src/jobs/types.ts"],"names":[],"mappings":""}
@@ -1 +1 @@
1
- {"version":3,"file":"main.d.ts","sourceRoot":"","sources":["../src/main.tsx"],"names":[],"mappings":"AAAA,OAAO,KAAK,EAAE,aAAa,EAAc,MAAM,sBAAsB,CAAA;AACrE,OAAO,KAAK,EAAE,YAAY,EAAE,aAAa,EAAE,MAAM,0BAA0B,CAAA;AAO3E,MAAM,WAAW,gBAAiB,SAAQ,aAAa;IACrD,aAAa,CAAC,EAAE,MAAM,CAAA;CACvB;AAED,eAAO,MAAM,MAAM,GAAI,CAAC,SAAS,YAAY,EAAE,CAAC,SAAS,aAAa,CAAC,CAAC,CAAC,EAAE,SAAS,CAAC,EAAE,OAAO,gBAAgB,SAE7G,CAAA"}
1
+ {"version":3,"file":"main.d.ts","sourceRoot":"","sources":["../src/main.tsx"],"names":[],"mappings":"AAAA,OAAO,KAAK,EAAE,aAAa,EAAc,MAAM,sBAAsB,CAAA;AACrE,OAAO,KAAK,EAAE,YAAY,EAAE,aAAa,EAAE,MAAM,0BAA0B,CAAA;AAO3E,MAAM,WAAW,gBAAiB,SAAQ,aAAa;IACrD,aAAa,CAAC,EAAE,MAAM,CAAA;CACvB;AAED,eAAO,MAAM,MAAM,GAAI,CAAC,SAAS,YAAY,EAAE,CAAC,SAAS,aAAa,CAAC,CAAC,CAAC,WAAW,CAAC,SAAS,gBAAgB,SAE7G,CAAA"}
@@ -0,0 +1,13 @@
1
+ import { type ClassValue } from 'clsx';
2
+ /**
3
+ * The class-name merger every component in this package is written against, exported so a
4
+ * consuming application doesn't declare its own copy.
5
+ *
6
+ * This is deliberately NOT a re-export of `@/lib/utils`. That specifier is left verbatim in the
7
+ * build and resolves to the CONSUMER's vendored file, so re-exporting it would hand an app back
8
+ * its own function and fail outright wherever the `@` alias isn't configured. The vendored copy
9
+ * under `src/@/lib/` stays exactly as shadcn emits it, because the package's own components must
10
+ * keep resolving through the `@` contract.
11
+ */
12
+ export declare const cn: (...inputs: ClassValue[]) => string;
13
+ //# sourceMappingURL=utils.d.ts.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"utils.d.ts","sourceRoot":"","sources":["../src/utils.ts"],"names":[],"mappings":"AAAA,OAAO,EAAQ,KAAK,UAAU,EAAE,MAAM,MAAM,CAAA;AAG5C;;;;;;;;;GASG;AACH,eAAO,MAAM,EAAE,cAAe,UAAU,EAAE,KAAG,MAA+B,CAAA"}
package/build/utils.js ADDED
@@ -0,0 +1,14 @@
1
+ import { clsx } from 'clsx';
2
+ import { twMerge } from 'tailwind-merge';
3
+ /**
4
+ * The class-name merger every component in this package is written against, exported so a
5
+ * consuming application doesn't declare its own copy.
6
+ *
7
+ * This is deliberately NOT a re-export of `@/lib/utils`. That specifier is left verbatim in the
8
+ * build and resolves to the CONSUMER's vendored file, so re-exporting it would hand an app back
9
+ * its own function and fail outright wherever the `@` alias isn't configured. The vendored copy
10
+ * under `src/@/lib/` stays exactly as shadcn emits it, because the package's own components must
11
+ * keep resolving through the `@` contract.
12
+ */
13
+ export const cn = (...inputs) => twMerge(clsx(inputs));
14
+ //# sourceMappingURL=utils.js.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"utils.js","sourceRoot":"","sources":["../src/utils.ts"],"names":[],"mappings":"AAAA,OAAO,EAAE,IAAI,EAAmB,MAAM,MAAM,CAAA;AAC5C,OAAO,EAAE,OAAO,EAAE,MAAM,gBAAgB,CAAA;AAExC;;;;;;;;;GASG;AACH,MAAM,CAAC,MAAM,EAAE,GAAG,CAAC,GAAG,MAAoB,EAAU,EAAE,CAAC,OAAO,CAAC,IAAI,CAAC,MAAM,CAAC,CAAC,CAAA"}
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "@owlmeans/web-panel",
3
- "version": "0.1.18-rc.30",
3
+ "version": "0.1.18-rc.32",
4
4
  "license": "MIT",
5
5
  "type": "module",
6
6
  "scripts": {
@@ -40,35 +40,43 @@
40
40
  "default": "./build/consent/index.js",
41
41
  "module": "./build/consent/index.js",
42
42
  "types": "./build/consent/index.d.ts"
43
+ },
44
+ "./jobs": {
45
+ "import": "./build/jobs/index.js",
46
+ "require": "./build/jobs/index.js",
47
+ "default": "./build/jobs/index.js",
48
+ "module": "./build/jobs/index.js",
49
+ "types": "./build/jobs/index.d.ts"
43
50
  }
44
51
  },
45
52
  "dependencies": {
46
53
  "@hookform/resolvers": "^5.2.2",
47
- "@owlmeans/api-config-client": "^0.1.18-rc.11",
48
- "@owlmeans/auth": "^0.1.18-rc.8",
49
- "@owlmeans/auth-common": "^0.1.18-rc.11",
50
- "@owlmeans/basic-envelope": "^0.1.18-rc.10",
51
- "@owlmeans/client": "^0.1.18-rc.14",
52
- "@owlmeans/client-auth": "^0.1.18-rc.18",
53
- "@owlmeans/client-config": "^0.1.18-rc.10",
54
- "@owlmeans/client-context": "^0.1.18-rc.11",
55
- "@owlmeans/client-entrypoint": "^0.1.18-rc.11",
56
- "@owlmeans/client-flow": "^0.1.18-rc.15",
57
- "@owlmeans/client-i18n": "^0.1.18-rc.13",
58
- "@owlmeans/client-panel": "^0.1.18-rc.21",
59
- "@owlmeans/client-route": "^0.1.18-rc.11",
60
- "@owlmeans/config": "^0.1.18-rc.10",
61
- "@owlmeans/context": "^0.1.18-rc.7",
62
- "@owlmeans/entrypoint": "^0.1.18-rc.9",
63
- "@owlmeans/error": "^0.1.18-rc.7",
64
- "@owlmeans/flow": "^0.1.18-rc.12",
65
- "@owlmeans/i18n": "^0.1.18-rc.7",
66
- "@owlmeans/route": "^0.1.18-rc.7",
67
- "@owlmeans/web-client": "^0.1.18-rc.22",
68
- "@owlmeans/web-consent": "^0.1.18-rc.5",
69
- "@owlmeans/web-db": "^0.1.18-rc.12",
70
- "@owlmeans/web-flow": "^0.1.18-rc.15",
71
- "@owlmeans/web-router": "^0.1.18-rc.12",
54
+ "@owlmeans/api-config-client": "^0.1.18-rc.13",
55
+ "@owlmeans/auth": "^0.1.18-rc.9",
56
+ "@owlmeans/auth-common": "^0.1.18-rc.13",
57
+ "@owlmeans/basic-envelope": "^0.1.18-rc.12",
58
+ "@owlmeans/client": "^0.1.18-rc.16",
59
+ "@owlmeans/client-auth": "^0.1.18-rc.20",
60
+ "@owlmeans/client-config": "^0.1.18-rc.12",
61
+ "@owlmeans/client-context": "^0.1.18-rc.13",
62
+ "@owlmeans/client-entrypoint": "^0.1.18-rc.13",
63
+ "@owlmeans/client-flow": "^0.1.18-rc.17",
64
+ "@owlmeans/client-i18n": "^0.1.18-rc.15",
65
+ "@owlmeans/client-panel": "^0.1.18-rc.23",
66
+ "@owlmeans/client-route": "^0.1.18-rc.13",
67
+ "@owlmeans/config": "^0.1.18-rc.12",
68
+ "@owlmeans/context": "^0.1.18-rc.8",
69
+ "@owlmeans/entrypoint": "^0.1.18-rc.11",
70
+ "@owlmeans/error": "^0.1.18-rc.8",
71
+ "@owlmeans/flow": "^0.1.18-rc.14",
72
+ "@owlmeans/i18n": "^0.1.18-rc.8",
73
+ "@owlmeans/queue": "^0.1.18-rc.9",
74
+ "@owlmeans/route": "^0.1.18-rc.9",
75
+ "@owlmeans/web-client": "^0.1.18-rc.24",
76
+ "@owlmeans/web-consent": "^0.1.18-rc.7",
77
+ "@owlmeans/web-db": "^0.1.18-rc.14",
78
+ "@owlmeans/web-flow": "^0.1.18-rc.17",
79
+ "@owlmeans/web-router": "^0.1.18-rc.14",
72
80
  "i18next-browser-languagedetector": "^8.0.0",
73
81
  "qrcode.react": "^4.2.0",
74
82
  "react-google-recaptcha": "^3.1.0",
@@ -92,7 +100,7 @@
92
100
  },
93
101
  "devDependencies": {
94
102
  "@owlmeans/dep-config": "workspace:*",
95
- "@owlmeans/test-ui": "^0.1.18-rc.13",
103
+ "@owlmeans/test-ui": "^0.1.18-rc.15",
96
104
  "@radix-ui/react-label": "^2.1.0",
97
105
  "@radix-ui/react-navigation-menu": "^1.2.14",
98
106
  "@radix-ui/react-progress": "^1.1.0",
@@ -0,0 +1 @@
1
+ export * from './use-mobile.js'
@@ -0,0 +1,35 @@
1
+ import { useEffect, useState } from 'react'
2
+
3
+ /** Tailwind's `md` — the width at which the navigation shell swaps its side menu for the bar. */
4
+ export const MOBILE_BREAKPOINT = 768
5
+
6
+ /**
7
+ * Whether the viewport is narrower than Tailwind's `md`, for a component that has to pick a tree
8
+ * rather than render both and hide one with `md:hidden`.
9
+ *
10
+ * It matches a media query instead of listening for `resize` the way `useBreakPoint` does: the
11
+ * browser evaluates the query itself and notifies only when the answer flips, so dragging a window
12
+ * across the whole width costs one render rather than one per frame.
13
+ *
14
+ * The answer is `false` before the first effect and on a server render, because `window` is the
15
+ * only thing that knows the width. That makes the desktop tree the one server-rendered HTML and
16
+ * the first client paint agree on, so hydration never mismatches.
17
+ */
18
+ export const useIsMobile = (): boolean => {
19
+ const [isMobile, setIsMobile] = useState(false)
20
+
21
+ useEffect(() => {
22
+ if (typeof window === 'undefined' || window.matchMedia == null) {
23
+ return
24
+ }
25
+
26
+ const query = window.matchMedia(`(max-width: ${MOBILE_BREAKPOINT - 1}px)`)
27
+ const read = () => setIsMobile(query.matches)
28
+ read()
29
+ query.addEventListener('change', read)
30
+
31
+ return () => query.removeEventListener('change', read)
32
+ }, [])
33
+
34
+ return isMobile
35
+ }
package/src/index.ts CHANGED
@@ -5,5 +5,7 @@ export * from './exports.js'
5
5
  export * from './context.js'
6
6
  export * from './entrypoints.js'
7
7
  export * from './components/index.js'
8
+ export * from './hooks/index.js'
9
+ export * from './utils.js'
8
10
 
9
11
  export * from '@owlmeans/client-panel'
@@ -0,0 +1,78 @@
1
+ import type { FC } from 'react'
2
+ import { useMemo } from 'react'
3
+ import { JobState } from '@owlmeans/queue'
4
+ import type { JobRecord } from '@owlmeans/queue'
5
+ import { Progress } from '@/components/ui/progress'
6
+ import { cn } from '@/lib/utils'
7
+ import type { JobProps, JobStatusProps } from './types.js'
8
+
9
+ /**
10
+ * A job's progress as a percentage, or `undefined` when there is nothing to show yet.
11
+ *
12
+ * `JobRecord.progress` is deliberately `unknown` — a processor reports whatever it counts — so the
13
+ * three shapes worth understanding are read here and everything else falls through to the
14
+ * indeterminate bar, which is the honest answer for "running, no idea how far".
15
+ */
16
+ export const jobProgressValue = (job: JobRecord): number | undefined => {
17
+ if (job.state === JobState.Completed) {
18
+ return 100
19
+ }
20
+ const progress = job.progress
21
+ const value = typeof progress === 'number' ? progress
22
+ : typeof progress === 'object' && progress != null
23
+ ? percentOf(progress as Record<string, unknown>)
24
+ : undefined
25
+
26
+ return value == null ? undefined : Math.max(0, Math.min(100, value))
27
+ }
28
+
29
+ const percentOf = (progress: Record<string, unknown>): number | undefined => {
30
+ if (typeof progress.percent === 'number') {
31
+ return progress.percent
32
+ }
33
+ const { done, total } = progress
34
+ if (typeof done === 'number' && typeof total === 'number' && total > 0) {
35
+ return (done / total) * 100
36
+ }
37
+
38
+ return undefined
39
+ }
40
+
41
+ /**
42
+ * The bar for one job. A job with nothing to report animates indeterminately rather than sitting
43
+ * at zero, because zero and "the processor never called `progress()`" look identical otherwise.
44
+ */
45
+ export const JobProgress: FC<JobProps> = ({ job, className, style }) => {
46
+ const value = useMemo(() => jobProgressValue(job), [job.state, job.progress])
47
+
48
+ return <Progress
49
+ data-slot="job-progress"
50
+ value={value}
51
+ className={cn('w-full', className)}
52
+ style={style}
53
+ />
54
+ }
55
+
56
+ const STATE_STYLE: Record<JobState, string> = {
57
+ [JobState.Waiting]: 'border-border bg-muted text-muted-foreground',
58
+ [JobState.Delayed]: 'border-border bg-muted text-muted-foreground',
59
+ [JobState.Active]: 'border-border bg-accent text-accent-foreground',
60
+ [JobState.Completed]: 'border-primary/40 bg-primary/10 text-primary',
61
+ [JobState.Failed]: 'border-destructive/40 bg-destructive/10 text-destructive',
62
+ [JobState.Unknown]: 'border-border bg-muted text-muted-foreground',
63
+ }
64
+
65
+ /** The state pill. `data-state` carries the raw state, so a test never keys on the wording. */
66
+ export const JobStatus: FC<JobStatusProps> = ({ job, labels, className, style }) => {
67
+ const state = job.state ?? JobState.Unknown
68
+
69
+ return <span
70
+ data-slot="job-status"
71
+ data-state={state}
72
+ className={cn(
73
+ 'inline-flex items-center rounded-full border px-2 py-0.5 text-xs font-medium',
74
+ STATE_STYLE[state], className
75
+ )}
76
+ style={style}
77
+ >{labels?.[state] ?? state}</span>
78
+ }
@@ -0,0 +1,4 @@
1
+ export type * from './types.js'
2
+
3
+ export * from './component.js'
4
+ export * from './toasts.js'
@@ -0,0 +1,41 @@
1
+ import { useEffect, useRef } from 'react'
2
+ import { toast } from 'sonner'
3
+ import { isSettled, JobState } from '@owlmeans/queue'
4
+ import type { JobRecord } from '@owlmeans/queue'
5
+ import type { JobToastOptions } from './types.js'
6
+
7
+ /**
8
+ * Announce jobs as they finish, on the `Toaster` the layout already mounts.
9
+ *
10
+ * Hand it whatever the screen is already showing — `useJobs()` from `@owlmeans/client-job` maps
11
+ * straight onto it — and it raises one toast per job the first time that job settles.
12
+ *
13
+ * **The first pass never toasts.** A screen opening onto a store seeded with yesterday's finished
14
+ * jobs would otherwise fire a stack of them at once, so everything already settled when this
15
+ * mounts is recorded as announced and only what settles afterwards is reported.
16
+ */
17
+ export const useJobToasts = (jobs: JobRecord[], opts?: JobToastOptions): void => {
18
+ const announced = useRef<Set<string>>(new Set())
19
+ const primed = useRef(false)
20
+ // Re-run on what actually decides a toast, not on the array identity a caller rebuilds per render.
21
+ const settlement = jobs.map(job => `${job.id}:${job.state}`).join(',')
22
+
23
+ useEffect(() => {
24
+ jobs.forEach(job => {
25
+ if (job.id == null || !isSettled(job.state) || announced.current.has(job.id)) {
26
+ return
27
+ }
28
+ announced.current.add(job.id)
29
+ if (!primed.current) {
30
+ return
31
+ }
32
+ const message = opts?.message?.(job) ?? job.name
33
+ if (job.state === JobState.Completed) {
34
+ toast.success(message)
35
+ } else {
36
+ toast.error(job.error != null && job.error !== '' ? `${String(message)}: ${job.error}` : message)
37
+ }
38
+ })
39
+ primed.current = true
40
+ }, [settlement])
41
+ }
@@ -0,0 +1,23 @@
1
+ import type { ReactNode } from 'react'
2
+ import type { JobRecord, JobState } from '@owlmeans/queue'
3
+ import type { StyledProps } from '../components/types.js'
4
+
5
+ export interface JobProps extends StyledProps {
6
+ job: JobRecord
7
+ }
8
+
9
+ export interface JobStatusProps extends JobProps {
10
+ /**
11
+ * What each state is called on screen.
12
+ *
13
+ * There is no packaged wording: the states are broker vocabulary, and the sentence an app wants
14
+ * for them ("Queued", "Rendering", "Ready") is the app's own copy in the app's own namespace.
15
+ * Absent a label the raw state is rendered, which is data rather than an untranslated string.
16
+ */
17
+ labels?: Partial<Record<JobState, ReactNode>>
18
+ }
19
+
20
+ export interface JobToastOptions {
21
+ /** What the toast says. The job's own name when omitted. */
22
+ message?: (job: JobRecord) => ReactNode
23
+ }
package/src/utils.ts ADDED
@@ -0,0 +1,14 @@
1
+ import { clsx, type ClassValue } from 'clsx'
2
+ import { twMerge } from 'tailwind-merge'
3
+
4
+ /**
5
+ * The class-name merger every component in this package is written against, exported so a
6
+ * consuming application doesn't declare its own copy.
7
+ *
8
+ * This is deliberately NOT a re-export of `@/lib/utils`. That specifier is left verbatim in the
9
+ * build and resolves to the CONSUMER's vendored file, so re-exporting it would hand an app back
10
+ * its own function and fail outright wherever the `@` alias isn't configured. The vendored copy
11
+ * under `src/@/lib/` stays exactly as shadcn emits it, because the package's own components must
12
+ * keep resolving through the `@` contract.
13
+ */
14
+ export const cn = (...inputs: ClassValue[]): string => twMerge(clsx(inputs))