@bgord/ui 0.5.1 → 0.5.4
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/dist/components/dialog.d.ts +4 -0
- package/dist/components/index.d.ts +2 -0
- package/dist/components/revalidate-on-focus.d.ts +1 -0
- package/dist/hooks/index.d.ts +2 -0
- package/dist/hooks/use-click-outside.d.ts +2 -0
- package/dist/hooks/use-scroll-lock.d.ts +1 -0
- package/dist/index.js +182 -20
- package/dist/services/auth-guard.d.ts +9 -0
- package/dist/services/cookies.d.ts +3 -0
- package/dist/services/copy-to-clipboard.d.ts +10 -0
- package/dist/services/credentials.d.ts +9 -0
- package/dist/services/index.d.ts +5 -1
- package/dist/services/noop.d.ts +1 -0
- package/package.json +12 -11
- package/readme.md +9 -1
|
@@ -0,0 +1 @@
|
|
|
1
|
+
export declare function RevalidateOnFocus(): null;
|
package/dist/hooks/index.d.ts
CHANGED
|
@@ -1,3 +1,4 @@
|
|
|
1
|
+
export * from "./use-click-outside";
|
|
1
2
|
export * from "./use-client-filter";
|
|
2
3
|
export * from "./use-exit-action";
|
|
3
4
|
export * from "./use-field";
|
|
@@ -5,5 +6,6 @@ export * from "./use-focus-shortcut";
|
|
|
5
6
|
export * from "./use-hover";
|
|
6
7
|
export * from "./use-language-selector";
|
|
7
8
|
export * from "./use-meta-enter-submit";
|
|
9
|
+
export * from "./use-scroll-lock";
|
|
8
10
|
export * from "./use-shortcuts";
|
|
9
11
|
export * from "./use-toggle";
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
export declare function useScrollLock(enabled?: boolean): void;
|
package/dist/index.js
CHANGED
|
@@ -6,6 +6,41 @@ function Button() {
|
|
|
6
6
|
children: "Click"
|
|
7
7
|
}, undefined, false, undefined, this);
|
|
8
8
|
}
|
|
9
|
+
// src/components/dialog.tsx
|
|
10
|
+
import { useEffect as useEffect6, useRef as useRef3 } from "react";
|
|
11
|
+
|
|
12
|
+
// src/hooks/use-click-outside.ts
|
|
13
|
+
import { useEffect } from "react";
|
|
14
|
+
function useClickOutside(ref, handler) {
|
|
15
|
+
useEffect(() => {
|
|
16
|
+
if (typeof document === "undefined")
|
|
17
|
+
return;
|
|
18
|
+
function listener(event) {
|
|
19
|
+
const el = ref.current;
|
|
20
|
+
if (!el)
|
|
21
|
+
return;
|
|
22
|
+
if (el.contains(event.target)) {
|
|
23
|
+
if (event.target === el) {
|
|
24
|
+
const { left, right, top, bottom } = el.getBoundingClientRect();
|
|
25
|
+
const clientX = event instanceof MouseEvent ? event.clientX : event.touches[0].clientX;
|
|
26
|
+
const clientY = event instanceof MouseEvent ? event.clientY : event.touches[0].clientY;
|
|
27
|
+
const isInRect = clientX >= left && clientX <= right && clientY >= top && clientY <= bottom;
|
|
28
|
+
if (isInRect)
|
|
29
|
+
return;
|
|
30
|
+
} else {
|
|
31
|
+
return;
|
|
32
|
+
}
|
|
33
|
+
}
|
|
34
|
+
handler(event);
|
|
35
|
+
}
|
|
36
|
+
document.addEventListener("mousedown", listener);
|
|
37
|
+
document.addEventListener("touchstart", listener);
|
|
38
|
+
return () => {
|
|
39
|
+
document.removeEventListener("mousedown", listener);
|
|
40
|
+
document.removeEventListener("touchstart", listener);
|
|
41
|
+
};
|
|
42
|
+
}, [ref, handler]);
|
|
43
|
+
}
|
|
9
44
|
// src/hooks/use-client-filter.ts
|
|
10
45
|
import { useCallback, useMemo } from "react";
|
|
11
46
|
|
|
@@ -34,7 +69,7 @@ class Field {
|
|
|
34
69
|
}
|
|
35
70
|
|
|
36
71
|
// src/hooks/use-field.ts
|
|
37
|
-
import { useEffect, useState } from "react";
|
|
72
|
+
import { useEffect as useEffect2, useState } from "react";
|
|
38
73
|
import { useSearchParams } from "react-router";
|
|
39
74
|
var useFieldStrategyEnum;
|
|
40
75
|
((useFieldStrategyEnum2) => {
|
|
@@ -51,7 +86,7 @@ function useField(config) {
|
|
|
51
86
|
const candidate = new Field(value2);
|
|
52
87
|
_setCurrentValue(candidate.get());
|
|
53
88
|
};
|
|
54
|
-
|
|
89
|
+
useEffect2(() => {
|
|
55
90
|
const current = new Field(currentValue);
|
|
56
91
|
if (strategy === "params" /* params */) {
|
|
57
92
|
if (current.isEmpty()) {
|
|
@@ -130,12 +165,12 @@ function useExitAction(options) {
|
|
|
130
165
|
import { useCallback as useCallback2, useMemo as useMemo3, useRef } from "react";
|
|
131
166
|
|
|
132
167
|
// src/hooks/use-shortcuts.ts
|
|
133
|
-
import { useEffect as
|
|
168
|
+
import { useEffect as useEffect3, useMemo as useMemo2 } from "react";
|
|
134
169
|
import { tinykeys } from "tinykeys";
|
|
135
170
|
function useKeyboardShortcuts(config, options) {
|
|
136
171
|
const enabled = options?.enabled ?? true;
|
|
137
172
|
const memoizedConfig = useMemo2(() => config, [JSON.stringify(Object.keys(config))]);
|
|
138
|
-
|
|
173
|
+
useEffect3(() => {
|
|
139
174
|
if (!enabled)
|
|
140
175
|
return;
|
|
141
176
|
const unsubscribe = tinykeys(window, memoizedConfig);
|
|
@@ -215,7 +250,7 @@ function useHover({
|
|
|
215
250
|
}
|
|
216
251
|
// src/hooks/use-language-selector.tsx
|
|
217
252
|
import Cookies from "js-cookie";
|
|
218
|
-
import { useCallback as useCallback5, useEffect as
|
|
253
|
+
import { useCallback as useCallback5, useEffect as useEffect4 } from "react";
|
|
219
254
|
import { useRevalidator } from "react-router";
|
|
220
255
|
|
|
221
256
|
// src/services/translations.tsx
|
|
@@ -293,7 +328,7 @@ function useLanguageSelector(supportedLanguages) {
|
|
|
293
328
|
revalidator.revalidate();
|
|
294
329
|
}
|
|
295
330
|
}, [field.currentValue, field.changed]);
|
|
296
|
-
|
|
331
|
+
useEffect4(() => {
|
|
297
332
|
handleLanguageChange();
|
|
298
333
|
}, [handleLanguageChange]);
|
|
299
334
|
return field;
|
|
@@ -309,19 +344,138 @@ function useMetaEnterSubmit() {
|
|
|
309
344
|
}, []);
|
|
310
345
|
return useMemo4(() => ({ onKeyDown: handleMetaEnterSubmit }), [handleMetaEnterSubmit]);
|
|
311
346
|
}
|
|
312
|
-
// src/
|
|
313
|
-
|
|
314
|
-
|
|
315
|
-
|
|
316
|
-
|
|
317
|
-
|
|
318
|
-
|
|
319
|
-
|
|
320
|
-
|
|
321
|
-
|
|
322
|
-
|
|
323
|
-
|
|
347
|
+
// src/hooks/use-scroll-lock.ts
|
|
348
|
+
import { useEffect as useEffect5 } from "react";
|
|
349
|
+
function useScrollLock(enabled = true) {
|
|
350
|
+
useEffect5(() => {
|
|
351
|
+
if (typeof document === "undefined")
|
|
352
|
+
return;
|
|
353
|
+
const originalOverflow = document.body.style.overflow;
|
|
354
|
+
if (enabled) {
|
|
355
|
+
document.body.style.overflow = "hidden";
|
|
356
|
+
}
|
|
357
|
+
return () => {
|
|
358
|
+
document.body.style.overflow = originalOverflow;
|
|
359
|
+
};
|
|
360
|
+
}, [enabled]);
|
|
324
361
|
}
|
|
362
|
+
// src/components/dialog.tsx
|
|
363
|
+
import { jsxDEV as jsxDEV2 } from "react/jsx-dev-runtime";
|
|
364
|
+
function Dialog(props) {
|
|
365
|
+
const { toggle: dialog, rest } = extractUseToggle(props);
|
|
366
|
+
const ref = useRef3(null);
|
|
367
|
+
useEffect6(() => {
|
|
368
|
+
if (props.on) {
|
|
369
|
+
ref.current?.showModal();
|
|
370
|
+
} else {
|
|
371
|
+
ref.current?.close();
|
|
372
|
+
}
|
|
373
|
+
}, [props.on]);
|
|
374
|
+
useKeyboardShortcuts({ Escape: dialog.disable });
|
|
375
|
+
useScrollLock(props.on);
|
|
376
|
+
useClickOutside(ref, dialog.disable);
|
|
377
|
+
return /* @__PURE__ */ jsxDEV2("dialog", {
|
|
378
|
+
ref,
|
|
379
|
+
tabIndex: 0,
|
|
380
|
+
"aria-modal": "true",
|
|
381
|
+
"data-disp": props.on ? "flex" : "none",
|
|
382
|
+
"data-dir": "column",
|
|
383
|
+
"data-mx": "auto",
|
|
384
|
+
"data-p": "5",
|
|
385
|
+
"data-position": "fixed",
|
|
386
|
+
"data-z": "2",
|
|
387
|
+
"data-bg": "neutral-900",
|
|
388
|
+
"data-br": "xs",
|
|
389
|
+
"data-backdrop": "stronger",
|
|
390
|
+
"data-animation": "grow-fade-in",
|
|
391
|
+
...rest
|
|
392
|
+
}, undefined, false, undefined, this);
|
|
393
|
+
}
|
|
394
|
+
// src/components/revalidate-on-focus.tsx
|
|
395
|
+
import { useEffect as useEffect7 } from "react";
|
|
396
|
+
import { useRevalidator as useRevalidator2 } from "react-router";
|
|
397
|
+
function RevalidateOnFocus() {
|
|
398
|
+
const revalidator = useRevalidator2();
|
|
399
|
+
useEffect7(() => {
|
|
400
|
+
const onFocus = () => revalidator.revalidate();
|
|
401
|
+
window.addEventListener("focus", onFocus);
|
|
402
|
+
return () => window.removeEventListener("focus", onFocus);
|
|
403
|
+
}, [revalidator]);
|
|
404
|
+
return null;
|
|
405
|
+
}
|
|
406
|
+
// src/services/auth-guard.ts
|
|
407
|
+
import { redirect } from "react-router";
|
|
408
|
+
|
|
409
|
+
// src/services/cookies.ts
|
|
410
|
+
class Cookies2 {
|
|
411
|
+
static extractFrom(request) {
|
|
412
|
+
return request.headers.get("cookie") ?? "";
|
|
413
|
+
}
|
|
414
|
+
}
|
|
415
|
+
|
|
416
|
+
// src/services/auth-guard.ts
|
|
417
|
+
class AuthGuard {
|
|
418
|
+
API_URL;
|
|
419
|
+
constructor(BASE_URL) {
|
|
420
|
+
this.API_URL = `${BASE_URL}/api/auth`;
|
|
421
|
+
}
|
|
422
|
+
async getServerSession(request) {
|
|
423
|
+
const cookie = Cookies2.extractFrom(request);
|
|
424
|
+
const res = await fetch(`${this.API_URL}/get-session`, {
|
|
425
|
+
headers: { cookie, accept: "application/json" }
|
|
426
|
+
});
|
|
427
|
+
if (!res.ok)
|
|
428
|
+
return null;
|
|
429
|
+
const session = await res.json();
|
|
430
|
+
return session;
|
|
431
|
+
}
|
|
432
|
+
async requireSession(request) {
|
|
433
|
+
const session = await this.getServerSession(request);
|
|
434
|
+
if (session?.user)
|
|
435
|
+
return session;
|
|
436
|
+
throw redirect("/");
|
|
437
|
+
}
|
|
438
|
+
async requireNoSession(request, target = "/home") {
|
|
439
|
+
const session = await this.getServerSession(request);
|
|
440
|
+
if (session?.user)
|
|
441
|
+
throw redirect(target);
|
|
442
|
+
}
|
|
443
|
+
async removeSession(request, target = "/login") {
|
|
444
|
+
const cookie = Cookies2.extractFrom(request);
|
|
445
|
+
const res = await fetch(`${import.meta.env.VITE_API_URL}/api/auth/sign-out`, {
|
|
446
|
+
method: "POST",
|
|
447
|
+
headers: { cookie }
|
|
448
|
+
});
|
|
449
|
+
const headers = new Headers;
|
|
450
|
+
res.headers.forEach((value, key) => {
|
|
451
|
+
if (key.toLowerCase() === "set-cookie")
|
|
452
|
+
headers.append("set-cookie", value);
|
|
453
|
+
});
|
|
454
|
+
throw redirect(target, { headers });
|
|
455
|
+
}
|
|
456
|
+
}
|
|
457
|
+
// src/services/noop.ts
|
|
458
|
+
function noop() {}
|
|
459
|
+
|
|
460
|
+
// src/services/copy-to-clipboard.ts
|
|
461
|
+
var defaultOnCopyToClipboardFailure = () => console.warn("Copying to clipboard not supported");
|
|
462
|
+
async function copyToClipboard(options) {
|
|
463
|
+
const onFailure = options.onFailure ?? defaultOnCopyToClipboardFailure;
|
|
464
|
+
const onSuccess = options.onSuccess ?? noop;
|
|
465
|
+
if (!navigator.clipboard)
|
|
466
|
+
onFailure();
|
|
467
|
+
try {
|
|
468
|
+
await navigator.clipboard.writeText(options.text);
|
|
469
|
+
onSuccess();
|
|
470
|
+
} catch (error) {
|
|
471
|
+
onFailure(error);
|
|
472
|
+
}
|
|
473
|
+
}
|
|
474
|
+
// src/services/credentials.ts
|
|
475
|
+
var Credentials = {
|
|
476
|
+
email: { inputMode: "email", autoComplete: "email", autoCapitalize: "none", spellCheck: "false" },
|
|
477
|
+
password: { new: { autoComplete: "new-password" }, current: { autoComplete: "current-password" } }
|
|
478
|
+
};
|
|
325
479
|
// src/services/etag.ts
|
|
326
480
|
class ETag {
|
|
327
481
|
static fromRevision(revision) {
|
|
@@ -423,6 +577,7 @@ class WeakETag {
|
|
|
423
577
|
export {
|
|
424
578
|
useTranslations,
|
|
425
579
|
useToggle,
|
|
580
|
+
useScrollLock,
|
|
426
581
|
usePluralize,
|
|
427
582
|
useMetaEnterSubmit,
|
|
428
583
|
useLanguageSelector,
|
|
@@ -434,18 +589,25 @@ export {
|
|
|
434
589
|
useField,
|
|
435
590
|
useExitAction,
|
|
436
591
|
useClientFilter,
|
|
592
|
+
useClickOutside,
|
|
437
593
|
pluralize,
|
|
594
|
+
noop,
|
|
438
595
|
getSafeWindow,
|
|
439
596
|
extractUseToggle,
|
|
440
597
|
exec,
|
|
598
|
+
copyToClipboard,
|
|
441
599
|
WeakETag,
|
|
442
600
|
TranslationsContext,
|
|
443
601
|
Rhythm,
|
|
602
|
+
RevalidateOnFocus,
|
|
444
603
|
LocalFields,
|
|
445
604
|
Form,
|
|
446
605
|
Fields,
|
|
447
606
|
Field,
|
|
448
607
|
ETag,
|
|
449
|
-
|
|
450
|
-
|
|
608
|
+
Dialog,
|
|
609
|
+
Credentials,
|
|
610
|
+
Cookies2 as Cookies,
|
|
611
|
+
Button,
|
|
612
|
+
AuthGuard
|
|
451
613
|
};
|
|
@@ -0,0 +1,9 @@
|
|
|
1
|
+
import type { createAuthClient } from "better-auth/react";
|
|
2
|
+
export declare class AuthGuard<T extends ReturnType<typeof createAuthClient>["$Infer"]["Session"]> {
|
|
3
|
+
private readonly API_URL;
|
|
4
|
+
constructor(BASE_URL: string);
|
|
5
|
+
getServerSession(request: Request): Promise<T | null>;
|
|
6
|
+
requireSession(request: Request): Promise<T | null>;
|
|
7
|
+
requireNoSession(request: Request, target?: string): Promise<void>;
|
|
8
|
+
removeSession(request: Request, target?: string): Promise<void>;
|
|
9
|
+
}
|
|
@@ -0,0 +1,10 @@
|
|
|
1
|
+
type CopyToClipboardTextType = string;
|
|
2
|
+
type OnCopyToClipboardFailureType = (error?: unknown) => void;
|
|
3
|
+
type OnCopyToClipboardSuccessType = VoidFunction;
|
|
4
|
+
export type CopyToClipboardOptionsType = {
|
|
5
|
+
text: CopyToClipboardTextType;
|
|
6
|
+
onFailure?: OnCopyToClipboardFailureType;
|
|
7
|
+
onSuccess?: OnCopyToClipboardSuccessType;
|
|
8
|
+
};
|
|
9
|
+
export declare function copyToClipboard(options: CopyToClipboardOptionsType): Promise<void>;
|
|
10
|
+
export {};
|
package/dist/services/index.d.ts
CHANGED
|
@@ -1,10 +1,14 @@
|
|
|
1
|
-
export * from "./
|
|
1
|
+
export * from "./auth-guard";
|
|
2
|
+
export * from "./cookies";
|
|
3
|
+
export * from "./copy-to-clipboard";
|
|
4
|
+
export * from "./credentials";
|
|
2
5
|
export * from "./etag";
|
|
3
6
|
export * from "./exec";
|
|
4
7
|
export * from "./field";
|
|
5
8
|
export * from "./fields";
|
|
6
9
|
export * from "./form";
|
|
7
10
|
export * from "./get-safe-window";
|
|
11
|
+
export * from "./noop";
|
|
8
12
|
export * from "./pluralize";
|
|
9
13
|
export * from "./rhythm";
|
|
10
14
|
export * from "./translations";
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
export declare function noop(): void;
|
package/package.json
CHANGED
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
{
|
|
2
2
|
"name": "@bgord/ui",
|
|
3
|
-
"version": "0.5.
|
|
3
|
+
"version": "0.5.4",
|
|
4
4
|
"type": "module",
|
|
5
5
|
"exports": {
|
|
6
6
|
".": {
|
|
@@ -12,9 +12,9 @@
|
|
|
12
12
|
"dist"
|
|
13
13
|
],
|
|
14
14
|
"peerDependencies": {
|
|
15
|
-
"react": "19.1.
|
|
16
|
-
"react-dom": "19.1.
|
|
17
|
-
"react-router": "7.
|
|
15
|
+
"react": "19.1.1",
|
|
16
|
+
"react-dom": "19.1.1",
|
|
17
|
+
"react-router": "7.7.1"
|
|
18
18
|
},
|
|
19
19
|
"scripts": {
|
|
20
20
|
"build:js": "bun build src/index.ts --format esm --outdir dist --packages external --external react --external react-dom --external react/jsx-runtime --external react-router",
|
|
@@ -29,21 +29,22 @@
|
|
|
29
29
|
"@commitlint/cli": "19.8.1",
|
|
30
30
|
"@commitlint/config-conventional": "19.8.1",
|
|
31
31
|
"@happy-dom/global-registrator": "18.0.1",
|
|
32
|
-
"@testing-library/dom": "10.4.
|
|
33
|
-
"@testing-library/jest-dom": "6.6.
|
|
32
|
+
"@testing-library/dom": "10.4.1",
|
|
33
|
+
"@testing-library/jest-dom": "6.6.4",
|
|
34
34
|
"@testing-library/react": "16.3.0",
|
|
35
35
|
"@testing-library/user-event": "14.6.1",
|
|
36
|
-
"@types/bun": "1.2.
|
|
36
|
+
"@types/bun": "1.2.19",
|
|
37
37
|
"@types/js-cookie": "^3.0.6",
|
|
38
|
-
"@types/react": "19.1.
|
|
39
|
-
"@types/react-dom": "19.1.
|
|
40
|
-
"cspell": "9.
|
|
41
|
-
"knip": "5.
|
|
38
|
+
"@types/react": "19.1.9",
|
|
39
|
+
"@types/react-dom": "19.1.7",
|
|
40
|
+
"cspell": "9.2.0",
|
|
41
|
+
"knip": "5.62.0",
|
|
42
42
|
"lefthook": "1.12.2",
|
|
43
43
|
"only-allow": "1.2.1",
|
|
44
44
|
"shellcheck": "3.1.0"
|
|
45
45
|
},
|
|
46
46
|
"dependencies": {
|
|
47
|
+
"better-auth": "1.3.4",
|
|
47
48
|
"js-cookie": "3.0.5",
|
|
48
49
|
"polish-plurals": "1.1.0",
|
|
49
50
|
"tinykeys": "3.0.0"
|
package/readme.md
CHANGED
|
@@ -26,7 +26,10 @@ Run the tests
|
|
|
26
26
|
src/
|
|
27
27
|
├── components
|
|
28
28
|
│ ├── button.tsx
|
|
29
|
+
│ ├── dialog.tsx
|
|
30
|
+
│ └── revalidate-on-focus.tsx
|
|
29
31
|
├── hooks
|
|
32
|
+
│ ├── use-click-outside.ts
|
|
30
33
|
│ ├── use-client-filter.ts
|
|
31
34
|
│ ├── use-exit-action.ts
|
|
32
35
|
│ ├── use-field.ts
|
|
@@ -34,16 +37,21 @@ src/
|
|
|
34
37
|
│ ├── use-hover.ts
|
|
35
38
|
│ ├── use-language-selector.tsx
|
|
36
39
|
│ ├── use-meta-enter-submit.tsx
|
|
40
|
+
│ ├── use-scroll-lock.ts
|
|
37
41
|
│ ├── use-shortcuts.ts
|
|
38
42
|
│ └── use-toggle.ts
|
|
39
43
|
└── services
|
|
40
|
-
├──
|
|
44
|
+
├── auth-guard.ts
|
|
45
|
+
├── cookies.ts
|
|
46
|
+
├── copy-to-clipboard.ts
|
|
47
|
+
├── credentials.ts
|
|
41
48
|
├── etag.ts
|
|
42
49
|
├── exec.ts
|
|
43
50
|
├── field.ts
|
|
44
51
|
├── fields.ts
|
|
45
52
|
├── form.ts
|
|
46
53
|
├── get-safe-window.ts
|
|
54
|
+
├── noop.ts
|
|
47
55
|
├── pluralize.ts
|
|
48
56
|
├── rhythm.ts
|
|
49
57
|
├── translations.tsx
|