@seedgrid/fe-core 2026.4.20 → 2026.4.21

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.
@@ -409,6 +409,103 @@
409
409
  }
410
410
  }
411
411
  },
412
+ {
413
+ "componentId": "hook.use-debounced-value",
414
+ "exportName": "useDebouncedValue",
415
+ "sgMeta": {
416
+ "version": "0.1",
417
+ "componentId": "hook.use-debounced-value",
418
+ "package": "@seedgrid/fe-core",
419
+ "exportName": "useDebouncedValue",
420
+ "slug": "use-debounced-value",
421
+ "displayName": "Use Debounced Value",
422
+ "category": "hook",
423
+ "subcategory": "interaction",
424
+ "description": "React hook that returns a debounced version of a value with optional normalization before commit.",
425
+ "tags": [
426
+ "hook",
427
+ "debounce",
428
+ "search",
429
+ "filter",
430
+ "input"
431
+ ],
432
+ "capabilities": [
433
+ "delay",
434
+ "normalize",
435
+ "typed-value",
436
+ "react-hook"
437
+ ],
438
+ "fieldSemantics": [
439
+ "search",
440
+ "filter",
441
+ "input",
442
+ "debounce"
443
+ ],
444
+ "props": [
445
+ {
446
+ "name": "value",
447
+ "type": "T",
448
+ "required": true,
449
+ "description": "Current source value that should be debounced.",
450
+ "semanticRole": "value"
451
+ },
452
+ {
453
+ "name": "delayMs",
454
+ "type": "number",
455
+ "required": true,
456
+ "description": "Debounce delay in milliseconds before the debounced value updates.",
457
+ "semanticRole": "behavior"
458
+ },
459
+ {
460
+ "name": "normalize",
461
+ "type": "(nextValue: T) => T",
462
+ "required": false,
463
+ "description": "Optional normalization function applied before the debounced value is stored.",
464
+ "semanticRole": "behavior"
465
+ }
466
+ ],
467
+ "states": [
468
+ "idle",
469
+ "pending",
470
+ "debounced"
471
+ ]
472
+ },
473
+ "aiHints": {
474
+ "version": "0.1",
475
+ "preferredUseCases": [
476
+ "Search inputs that should wait before querying paginated APIs.",
477
+ "Filter forms that should debounce local or remote state synchronization.",
478
+ "Shared debounce logic for multiple domain modules without pulling feature config into the core package."
479
+ ],
480
+ "avoidUseCases": [
481
+ "Immediate form validation that must react to every keystroke.",
482
+ "Complex stream composition better handled by dedicated observable pipelines."
483
+ ],
484
+ "synonyms": [
485
+ "debounced search",
486
+ "debounced input",
487
+ "debounced state",
488
+ "search debounce"
489
+ ],
490
+ "relatedEntityFields": [
491
+ "search",
492
+ "filter",
493
+ "query",
494
+ "text input"
495
+ ],
496
+ "compositionHints": [
497
+ "Wrap domain-specific normalization or min-length logic outside the hook and keep this hook generic.",
498
+ "Use with server-side pagination so list fetches are triggered only after the debounced value settles."
499
+ ],
500
+ "rankingSignals": {
501
+ "freeText": 0.3,
502
+ "structuredChoice": 0.25,
503
+ "date": 0,
504
+ "number": 0,
505
+ "denseLayout": 0.05
506
+ }
507
+ }
508
+ },
412
509
  {
413
510
  "componentId": "factory.api-client",
414
511
  "exportName": "createApiClient",
@@ -552,6 +649,92 @@
552
649
  }
553
650
  }
554
651
  },
652
+ {
653
+ "componentId": "utility.api-errors",
654
+ "exportName": "extractApiErrorMessage",
655
+ "sgMeta": {
656
+ "version": "0.1",
657
+ "componentId": "utility.api-errors",
658
+ "package": "@seedgrid/fe-core",
659
+ "exportName": "extractApiErrorMessage",
660
+ "slug": "extract-api-error-message",
661
+ "displayName": "API Error Message Extractor",
662
+ "category": "utility",
663
+ "subcategory": "http",
664
+ "description": "Reads API problem payloads and extracts the best user-facing message, prioritizing RFC7807 violations before generic detail/title fields.",
665
+ "tags": [
666
+ "api",
667
+ "http",
668
+ "error",
669
+ "rfc7807",
670
+ "validation"
671
+ ],
672
+ "capabilities": [
673
+ "api-client-error",
674
+ "rfc7807",
675
+ "violations",
676
+ "error-message",
677
+ "json-string-body"
678
+ ],
679
+ "fieldSemantics": [
680
+ "error",
681
+ "validation",
682
+ "problem-details",
683
+ "http"
684
+ ],
685
+ "props": [
686
+ {
687
+ "name": "error",
688
+ "type": "unknown",
689
+ "required": true,
690
+ "description": "ApiClientError, ApiClientError-like object, Error instance, or unknown thrown value to inspect.",
691
+ "semanticRole": "data"
692
+ }
693
+ ],
694
+ "states": [
695
+ "empty",
696
+ "problem-details",
697
+ "violations",
698
+ "fallback-message"
699
+ ]
700
+ },
701
+ "aiHints": {
702
+ "version": "0.1",
703
+ "preferredUseCases": [
704
+ "Showing API validation or problem-detail messages in UI toasts, whistles, dialogs, or notices.",
705
+ "Normalizing backend RFC7807 responses before mapping them to feature-specific fallback translations.",
706
+ "Handling cases where errors cross bundle boundaries and no longer satisfy instanceof ApiClientError."
707
+ ],
708
+ "avoidUseCases": [
709
+ "Client-side form validation unrelated to API responses.",
710
+ "Flows that need full structured problem objects rather than a single human-readable message."
711
+ ],
712
+ "synonyms": [
713
+ "rfc7807 parser",
714
+ "problem details",
715
+ "api validation message",
716
+ "violations message"
717
+ ],
718
+ "relatedEntityFields": [
719
+ "responseBody",
720
+ "detail",
721
+ "title",
722
+ "violations",
723
+ "errors"
724
+ ],
725
+ "compositionHints": [
726
+ "Call extractApiErrorMessage(error) first, then apply feature-specific server/network/html fallbacks only if needed.",
727
+ "Use alongside createApiClient so ApiClientError.responseBody is preserved end-to-end."
728
+ ],
729
+ "rankingSignals": {
730
+ "freeText": 0.35,
731
+ "structuredChoice": 0.2,
732
+ "date": 0,
733
+ "number": 0,
734
+ "denseLayout": 0.05
735
+ }
736
+ }
737
+ },
555
738
  {
556
739
  "componentId": "utility.exception-capture",
557
740
  "exportName": "captureException",
@@ -0,0 +1,9 @@
1
+ export declare function isApiClientErrorLike(error: unknown): error is {
2
+ message?: unknown;
3
+ responseBody?: unknown;
4
+ detail?: unknown;
5
+ status?: unknown;
6
+ };
7
+ export declare function extractApiErrorMessage(error: unknown): string | null;
8
+ export declare function readApiErrorMessage(body: unknown): string | null;
9
+ //# sourceMappingURL=api-errors.d.ts.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"api-errors.d.ts","sourceRoot":"","sources":["../../src/http/api-errors.ts"],"names":[],"mappings":"AAMA,wBAAgB,oBAAoB,CAClC,KAAK,EAAE,OAAO,GACb,KAAK,IAAI;IACV,OAAO,CAAC,EAAE,OAAO,CAAC;IAClB,YAAY,CAAC,EAAE,OAAO,CAAC;IACvB,MAAM,CAAC,EAAE,OAAO,CAAC;IACjB,MAAM,CAAC,EAAE,OAAO,CAAC;CAClB,CAEA;AAED,wBAAgB,sBAAsB,CAAC,KAAK,EAAE,OAAO,GAAG,MAAM,GAAG,IAAI,CAqBpE;AAED,wBAAgB,mBAAmB,CAAC,IAAI,EAAE,OAAO,GAAG,MAAM,GAAG,IAAI,CAoChE"}
@@ -0,0 +1,78 @@
1
+ // seedgrid:managed
2
+ import { ApiClientError } from "./api-client";
3
+ export function isApiClientErrorLike(error) {
4
+ return Boolean(error && typeof error === "object");
5
+ }
6
+ export function extractApiErrorMessage(error) {
7
+ if (error instanceof ApiClientError) {
8
+ return (readApiErrorMessage(error.responseBody) ??
9
+ pickString(error.message));
10
+ }
11
+ if (isApiClientErrorLike(error)) {
12
+ return (readApiErrorMessage(error.responseBody) ??
13
+ pickString(error.message) ??
14
+ pickString(error.detail));
15
+ }
16
+ if (error instanceof Error) {
17
+ return pickString(error.message);
18
+ }
19
+ return null;
20
+ }
21
+ export function readApiErrorMessage(body) {
22
+ const normalizedBody = normalizeApiBody(body);
23
+ if (!normalizedBody || typeof normalizedBody !== "object") {
24
+ return pickString(normalizedBody);
25
+ }
26
+ const record = normalizedBody;
27
+ if (Array.isArray(record.violations)) {
28
+ for (const entry of record.violations) {
29
+ const violationMessage = readRecordMessage(entry);
30
+ if (violationMessage) {
31
+ return violationMessage;
32
+ }
33
+ }
34
+ }
35
+ if (Array.isArray(record.errors)) {
36
+ for (const entry of record.errors) {
37
+ const nestedMessage = readRecordMessage(entry);
38
+ if (nestedMessage) {
39
+ return nestedMessage;
40
+ }
41
+ }
42
+ }
43
+ return (pickString(record.userMessage) ??
44
+ pickString(record.detail) ??
45
+ pickString(record.message) ??
46
+ pickString(record.error) ??
47
+ pickString(record.title));
48
+ }
49
+ function normalizeApiBody(body) {
50
+ if (typeof body !== "string") {
51
+ return body;
52
+ }
53
+ const normalized = body.trim();
54
+ if (!normalized) {
55
+ return body;
56
+ }
57
+ try {
58
+ return JSON.parse(normalized);
59
+ }
60
+ catch {
61
+ return body;
62
+ }
63
+ }
64
+ function readRecordMessage(value) {
65
+ if (!value || typeof value !== "object") {
66
+ return null;
67
+ }
68
+ const record = value;
69
+ return (pickString(record.userMessage) ??
70
+ pickString(record.message) ??
71
+ pickString(record.error) ??
72
+ pickString(record.description));
73
+ }
74
+ function pickString(value) {
75
+ return typeof value === "string" && value.trim().length > 0
76
+ ? value.trim()
77
+ : null;
78
+ }
@@ -0,0 +1,44 @@
1
+ type SgMetaPropV0 = {
2
+ name: string;
3
+ type: string;
4
+ required?: boolean;
5
+ default?: unknown;
6
+ description?: string;
7
+ semanticRole?: "value" | "label" | "validation" | "behavior" | "appearance" | "event" | "data";
8
+ bindable?: boolean;
9
+ };
10
+ type SgMetaV0 = {
11
+ version: "0.1";
12
+ componentId: string;
13
+ package: string;
14
+ exportName: string;
15
+ slug: string;
16
+ displayName: string;
17
+ category: string;
18
+ subcategory?: string;
19
+ description: string;
20
+ tags?: string[];
21
+ capabilities?: string[];
22
+ fieldSemantics?: string[];
23
+ props?: SgMetaPropV0[];
24
+ states?: string[];
25
+ };
26
+ type SgAiHintsV0 = {
27
+ version: "0.1";
28
+ preferredUseCases: string[];
29
+ avoidUseCases?: string[];
30
+ synonyms?: string[];
31
+ relatedEntityFields?: string[];
32
+ compositionHints?: string[];
33
+ rankingSignals?: {
34
+ freeText?: number;
35
+ structuredChoice?: number;
36
+ date?: number;
37
+ number?: number;
38
+ denseLayout?: number;
39
+ };
40
+ };
41
+ export declare const sgMeta: SgMetaV0;
42
+ export declare const aiHints: SgAiHintsV0;
43
+ export {};
44
+ //# sourceMappingURL=api-errors.meta.d.ts.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"api-errors.meta.d.ts","sourceRoot":"","sources":["../../src/http/api-errors.meta.ts"],"names":[],"mappings":"AAAA,KAAK,YAAY,GAAG;IAClB,IAAI,EAAE,MAAM,CAAC;IACb,IAAI,EAAE,MAAM,CAAC;IACb,QAAQ,CAAC,EAAE,OAAO,CAAC;IACnB,OAAO,CAAC,EAAE,OAAO,CAAC;IAClB,WAAW,CAAC,EAAE,MAAM,CAAC;IACrB,YAAY,CAAC,EACT,OAAO,GACP,OAAO,GACP,YAAY,GACZ,UAAU,GACV,YAAY,GACZ,OAAO,GACP,MAAM,CAAC;IACX,QAAQ,CAAC,EAAE,OAAO,CAAC;CACpB,CAAC;AAEF,KAAK,QAAQ,GAAG;IACd,OAAO,EAAE,KAAK,CAAC;IACf,WAAW,EAAE,MAAM,CAAC;IACpB,OAAO,EAAE,MAAM,CAAC;IAChB,UAAU,EAAE,MAAM,CAAC;IACnB,IAAI,EAAE,MAAM,CAAC;IACb,WAAW,EAAE,MAAM,CAAC;IACpB,QAAQ,EAAE,MAAM,CAAC;IACjB,WAAW,CAAC,EAAE,MAAM,CAAC;IACrB,WAAW,EAAE,MAAM,CAAC;IACpB,IAAI,CAAC,EAAE,MAAM,EAAE,CAAC;IAChB,YAAY,CAAC,EAAE,MAAM,EAAE,CAAC;IACxB,cAAc,CAAC,EAAE,MAAM,EAAE,CAAC;IAC1B,KAAK,CAAC,EAAE,YAAY,EAAE,CAAC;IACvB,MAAM,CAAC,EAAE,MAAM,EAAE,CAAC;CACnB,CAAC;AAEF,KAAK,WAAW,GAAG;IACjB,OAAO,EAAE,KAAK,CAAC;IACf,iBAAiB,EAAE,MAAM,EAAE,CAAC;IAC5B,aAAa,CAAC,EAAE,MAAM,EAAE,CAAC;IACzB,QAAQ,CAAC,EAAE,MAAM,EAAE,CAAC;IACpB,mBAAmB,CAAC,EAAE,MAAM,EAAE,CAAC;IAC/B,gBAAgB,CAAC,EAAE,MAAM,EAAE,CAAC;IAC5B,cAAc,CAAC,EAAE;QACf,QAAQ,CAAC,EAAE,MAAM,CAAC;QAClB,gBAAgB,CAAC,EAAE,MAAM,CAAC;QAC1B,IAAI,CAAC,EAAE,MAAM,CAAC;QACd,MAAM,CAAC,EAAE,MAAM,CAAC;QAChB,WAAW,CAAC,EAAE,MAAM,CAAC;KACtB,CAAC;CACH,CAAC;AAEF,eAAO,MAAM,MAAM,EAAE,QA+BpB,CAAC;AAEF,eAAO,MAAM,OAAO,EAAE,WA6BrB,CAAC"}
@@ -0,0 +1,60 @@
1
+ export const sgMeta = {
2
+ version: "0.1",
3
+ componentId: "utility.api-errors",
4
+ package: "@seedgrid/fe-core",
5
+ exportName: "extractApiErrorMessage",
6
+ slug: "extract-api-error-message",
7
+ displayName: "API Error Message Extractor",
8
+ category: "utility",
9
+ subcategory: "http",
10
+ description: "Reads API problem payloads and extracts the best user-facing message, prioritizing RFC7807 violations before generic detail/title fields.",
11
+ tags: ["api", "http", "error", "rfc7807", "validation"],
12
+ capabilities: [
13
+ "api-client-error",
14
+ "rfc7807",
15
+ "violations",
16
+ "error-message",
17
+ "json-string-body",
18
+ ],
19
+ fieldSemantics: ["error", "validation", "problem-details", "http"],
20
+ props: [
21
+ {
22
+ name: "error",
23
+ type: "unknown",
24
+ required: true,
25
+ description: "ApiClientError, ApiClientError-like object, Error instance, or unknown thrown value to inspect.",
26
+ semanticRole: "data",
27
+ },
28
+ ],
29
+ states: ["empty", "problem-details", "violations", "fallback-message"],
30
+ };
31
+ export const aiHints = {
32
+ version: "0.1",
33
+ preferredUseCases: [
34
+ "Showing API validation or problem-detail messages in UI toasts, whistles, dialogs, or notices.",
35
+ "Normalizing backend RFC7807 responses before mapping them to feature-specific fallback translations.",
36
+ "Handling cases where errors cross bundle boundaries and no longer satisfy instanceof ApiClientError.",
37
+ ],
38
+ avoidUseCases: [
39
+ "Client-side form validation unrelated to API responses.",
40
+ "Flows that need full structured problem objects rather than a single human-readable message.",
41
+ ],
42
+ synonyms: [
43
+ "rfc7807 parser",
44
+ "problem details",
45
+ "api validation message",
46
+ "violations message",
47
+ ],
48
+ relatedEntityFields: ["responseBody", "detail", "title", "violations", "errors"],
49
+ compositionHints: [
50
+ "Call extractApiErrorMessage(error) first, then apply feature-specific server/network/html fallbacks only if needed.",
51
+ "Use alongside createApiClient so ApiClientError.responseBody is preserved end-to-end.",
52
+ ],
53
+ rankingSignals: {
54
+ freeText: 0.35,
55
+ structuredChoice: 0.2,
56
+ date: 0,
57
+ number: 0,
58
+ denseLayout: 0.05,
59
+ },
60
+ };
package/dist/index.d.ts CHANGED
@@ -4,5 +4,7 @@ export * from "./i18n";
4
4
  export * from "./persistence";
5
5
  export * from "./http/api-exception-handler";
6
6
  export * from "./http/api-client";
7
+ export * from "./http/api-errors";
7
8
  export * from "./server";
9
+ export * from "./useDebouncedValue";
8
10
  //# sourceMappingURL=index.d.ts.map
@@ -1 +1 @@
1
- {"version":3,"file":"index.d.ts","sourceRoot":"","sources":["../src/index.ts"],"names":[],"mappings":"AAAA,cAAc,UAAU,CAAC;AACzB,cAAc,YAAY,CAAC;AAC3B,cAAc,QAAQ,CAAC;AACvB,cAAc,eAAe,CAAC;AAC9B,cAAc,8BAA8B,CAAC;AAC7C,cAAc,mBAAmB,CAAC;AAClC,cAAc,UAAU,CAAC"}
1
+ {"version":3,"file":"index.d.ts","sourceRoot":"","sources":["../src/index.ts"],"names":[],"mappings":"AAAA,cAAc,UAAU,CAAC;AACzB,cAAc,YAAY,CAAC;AAC3B,cAAc,QAAQ,CAAC;AACvB,cAAc,eAAe,CAAC;AAC9B,cAAc,8BAA8B,CAAC;AAC7C,cAAc,mBAAmB,CAAC;AAClC,cAAc,mBAAmB,CAAC;AAClC,cAAc,UAAU,CAAC;AACzB,cAAc,qBAAqB,CAAC"}
package/dist/index.js CHANGED
@@ -4,4 +4,6 @@ export * from "./i18n";
4
4
  export * from "./persistence";
5
5
  export * from "./http/api-exception-handler";
6
6
  export * from "./http/api-client";
7
+ export * from "./http/api-errors";
7
8
  export * from "./server";
9
+ export * from "./useDebouncedValue";
@@ -0,0 +1,2 @@
1
+ export declare function useDebouncedValue<T>(value: T, delayMs: number, normalize?: (nextValue: T) => T): T;
2
+ //# sourceMappingURL=useDebouncedValue.d.ts.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"useDebouncedValue.d.ts","sourceRoot":"","sources":["../src/useDebouncedValue.ts"],"names":[],"mappings":"AAKA,wBAAgB,iBAAiB,CAAC,CAAC,EACjC,KAAK,EAAE,CAAC,EACR,OAAO,EAAE,MAAM,EACf,SAAS,CAAC,EAAE,CAAC,SAAS,EAAE,CAAC,KAAK,CAAC,KAkBhC"}
@@ -0,0 +1,16 @@
1
+ // seedgrid:managed
2
+ "use client";
3
+ import { useEffect, useState } from "react";
4
+ export function useDebouncedValue(value, delayMs, normalize) {
5
+ const normalizeValue = normalize ?? ((nextValue) => nextValue);
6
+ const [debouncedValue, setDebouncedValue] = useState(() => normalizeValue(value));
7
+ useEffect(() => {
8
+ const timer = window.setTimeout(() => {
9
+ setDebouncedValue(normalizeValue(value));
10
+ }, Math.max(0, delayMs));
11
+ return () => {
12
+ window.clearTimeout(timer);
13
+ };
14
+ }, [delayMs, normalizeValue, value]);
15
+ return debouncedValue;
16
+ }
@@ -0,0 +1,44 @@
1
+ type SgMetaPropV0 = {
2
+ name: string;
3
+ type: string;
4
+ required?: boolean;
5
+ default?: unknown;
6
+ description?: string;
7
+ semanticRole?: "value" | "label" | "validation" | "behavior" | "appearance" | "event" | "data";
8
+ bindable?: boolean;
9
+ };
10
+ type SgMetaV0 = {
11
+ version: "0.1";
12
+ componentId: string;
13
+ package: string;
14
+ exportName: string;
15
+ slug: string;
16
+ displayName: string;
17
+ category: string;
18
+ subcategory?: string;
19
+ description: string;
20
+ tags?: string[];
21
+ capabilities?: string[];
22
+ fieldSemantics?: string[];
23
+ props?: SgMetaPropV0[];
24
+ states?: string[];
25
+ };
26
+ type SgAiHintsV0 = {
27
+ version: "0.1";
28
+ preferredUseCases: string[];
29
+ avoidUseCases?: string[];
30
+ synonyms?: string[];
31
+ relatedEntityFields?: string[];
32
+ compositionHints?: string[];
33
+ rankingSignals?: {
34
+ freeText?: number;
35
+ structuredChoice?: number;
36
+ date?: number;
37
+ number?: number;
38
+ denseLayout?: number;
39
+ };
40
+ };
41
+ export declare const sgMeta: SgMetaV0;
42
+ export declare const aiHints: SgAiHintsV0;
43
+ export {};
44
+ //# sourceMappingURL=useDebouncedValue.meta.d.ts.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"useDebouncedValue.meta.d.ts","sourceRoot":"","sources":["../src/useDebouncedValue.meta.ts"],"names":[],"mappings":"AAAA,KAAK,YAAY,GAAG;IAClB,IAAI,EAAE,MAAM,CAAC;IACb,IAAI,EAAE,MAAM,CAAC;IACb,QAAQ,CAAC,EAAE,OAAO,CAAC;IACnB,OAAO,CAAC,EAAE,OAAO,CAAC;IAClB,WAAW,CAAC,EAAE,MAAM,CAAC;IACrB,YAAY,CAAC,EACT,OAAO,GACP,OAAO,GACP,YAAY,GACZ,UAAU,GACV,YAAY,GACZ,OAAO,GACP,MAAM,CAAC;IACX,QAAQ,CAAC,EAAE,OAAO,CAAC;CACpB,CAAC;AAEF,KAAK,QAAQ,GAAG;IACd,OAAO,EAAE,KAAK,CAAC;IACf,WAAW,EAAE,MAAM,CAAC;IACpB,OAAO,EAAE,MAAM,CAAC;IAChB,UAAU,EAAE,MAAM,CAAC;IACnB,IAAI,EAAE,MAAM,CAAC;IACb,WAAW,EAAE,MAAM,CAAC;IACpB,QAAQ,EAAE,MAAM,CAAC;IACjB,WAAW,CAAC,EAAE,MAAM,CAAC;IACrB,WAAW,EAAE,MAAM,CAAC;IACpB,IAAI,CAAC,EAAE,MAAM,EAAE,CAAC;IAChB,YAAY,CAAC,EAAE,MAAM,EAAE,CAAC;IACxB,cAAc,CAAC,EAAE,MAAM,EAAE,CAAC;IAC1B,KAAK,CAAC,EAAE,YAAY,EAAE,CAAC;IACvB,MAAM,CAAC,EAAE,MAAM,EAAE,CAAC;CACnB,CAAC;AAEF,KAAK,WAAW,GAAG;IACjB,OAAO,EAAE,KAAK,CAAC;IACf,iBAAiB,EAAE,MAAM,EAAE,CAAC;IAC5B,aAAa,CAAC,EAAE,MAAM,EAAE,CAAC;IACzB,QAAQ,CAAC,EAAE,MAAM,EAAE,CAAC;IACpB,mBAAmB,CAAC,EAAE,MAAM,EAAE,CAAC;IAC/B,gBAAgB,CAAC,EAAE,MAAM,EAAE,CAAC;IAC5B,cAAc,CAAC,EAAE;QACf,QAAQ,CAAC,EAAE,MAAM,CAAC;QAClB,gBAAgB,CAAC,EAAE,MAAM,CAAC;QAC1B,IAAI,CAAC,EAAE,MAAM,CAAC;QACd,MAAM,CAAC,EAAE,MAAM,CAAC;QAChB,WAAW,CAAC,EAAE,MAAM,CAAC;KACtB,CAAC;CACH,CAAC;AAEF,eAAO,MAAM,MAAM,EAAE,QAsCpB,CAAC;AAEF,eAAO,MAAM,OAAO,EAAE,WAwBrB,CAAC"}
@@ -0,0 +1,63 @@
1
+ export const sgMeta = {
2
+ version: "0.1",
3
+ componentId: "hook.use-debounced-value",
4
+ package: "@seedgrid/fe-core",
5
+ exportName: "useDebouncedValue",
6
+ slug: "use-debounced-value",
7
+ displayName: "Use Debounced Value",
8
+ category: "hook",
9
+ subcategory: "interaction",
10
+ description: "React hook that returns a debounced version of a value with optional normalization before commit.",
11
+ tags: ["hook", "debounce", "search", "filter", "input"],
12
+ capabilities: ["delay", "normalize", "typed-value", "react-hook"],
13
+ fieldSemantics: ["search", "filter", "input", "debounce"],
14
+ props: [
15
+ {
16
+ name: "value",
17
+ type: "T",
18
+ required: true,
19
+ description: "Current source value that should be debounced.",
20
+ semanticRole: "value",
21
+ },
22
+ {
23
+ name: "delayMs",
24
+ type: "number",
25
+ required: true,
26
+ description: "Debounce delay in milliseconds before the debounced value updates.",
27
+ semanticRole: "behavior",
28
+ },
29
+ {
30
+ name: "normalize",
31
+ type: "(nextValue: T) => T",
32
+ required: false,
33
+ description: "Optional normalization function applied before the debounced value is stored.",
34
+ semanticRole: "behavior",
35
+ },
36
+ ],
37
+ states: ["idle", "pending", "debounced"],
38
+ };
39
+ export const aiHints = {
40
+ version: "0.1",
41
+ preferredUseCases: [
42
+ "Search inputs that should wait before querying paginated APIs.",
43
+ "Filter forms that should debounce local or remote state synchronization.",
44
+ "Shared debounce logic for multiple domain modules without pulling feature config into the core package.",
45
+ ],
46
+ avoidUseCases: [
47
+ "Immediate form validation that must react to every keystroke.",
48
+ "Complex stream composition better handled by dedicated observable pipelines.",
49
+ ],
50
+ synonyms: ["debounced search", "debounced input", "debounced state", "search debounce"],
51
+ relatedEntityFields: ["search", "filter", "query", "text input"],
52
+ compositionHints: [
53
+ "Wrap domain-specific normalization or min-length logic outside the hook and keep this hook generic.",
54
+ "Use with server-side pagination so list fetches are triggered only after the debounced value settles.",
55
+ ],
56
+ rankingSignals: {
57
+ freeText: 0.3,
58
+ structuredChoice: 0.25,
59
+ date: 0,
60
+ number: 0,
61
+ denseLayout: 0.05,
62
+ },
63
+ };
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "@seedgrid/fe-core",
3
- "version": "2026.4.20",
3
+ "version": "2026.4.21",
4
4
  "type": "module",
5
5
  "main": "dist/index.js",
6
6
  "types": "dist/index.d.ts",