@hjmds/react 1.13.1 → 1.14.0
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/agreement.d.ts.map +1 -1
- package/dist/agreement.js +5 -3
- package/dist/agreement.js.map +1 -1
- package/dist/content-transition.d.ts +7 -3
- package/dist/content-transition.d.ts.map +1 -1
- package/dist/content-transition.js +45 -2
- package/dist/content-transition.js.map +1 -1
- package/dist/date-entry.d.ts +9 -0
- package/dist/date-entry.d.ts.map +1 -0
- package/dist/date-entry.js +13 -0
- package/dist/date-entry.js.map +1 -0
- package/dist/document-resource.d.ts +3 -0
- package/dist/document-resource.d.ts.map +1 -0
- package/dist/document-resource.js +2 -0
- package/dist/document-resource.js.map +1 -0
- package/dist/effect-surface.d.ts.map +1 -1
- package/dist/effect-surface.js +2 -2
- package/dist/effect-surface.js.map +1 -1
- package/dist/evidence.d.ts +1 -1
- package/dist/evidence.js +1 -1
- package/dist/evidence.js.map +1 -1
- package/dist/field-group.d.ts +22 -0
- package/dist/field-group.d.ts.map +1 -0
- package/dist/field-group.js +20 -0
- package/dist/field-group.js.map +1 -0
- package/dist/forms.d.ts +1 -0
- package/dist/forms.d.ts.map +1 -1
- package/dist/forms.js +5 -3
- package/dist/forms.js.map +1 -1
- package/dist/image-comparison.d.ts +12 -0
- package/dist/image-comparison.d.ts.map +1 -0
- package/dist/image-comparison.js +14 -0
- package/dist/image-comparison.js.map +1 -0
- package/dist/internal/document-resource.d.ts +9 -0
- package/dist/internal/document-resource.d.ts.map +1 -0
- package/dist/internal/document-resource.js +37 -0
- package/dist/internal/document-resource.js.map +1 -0
- package/dist/internal/overlay-origin-motion.d.ts +13 -0
- package/dist/internal/overlay-origin-motion.d.ts.map +1 -0
- package/dist/internal/overlay-origin-motion.js +76 -0
- package/dist/internal/overlay-origin-motion.js.map +1 -0
- package/dist/overlays.d.ts +3 -0
- package/dist/overlays.d.ts.map +1 -1
- package/dist/overlays.js +16 -12
- package/dist/overlays.js.map +1 -1
- package/dist/popover.d.ts +3 -0
- package/dist/popover.d.ts.map +1 -1
- package/dist/popover.js +8 -4
- package/dist/popover.js.map +1 -1
- package/dist/portal.d.ts +3 -1
- package/dist/portal.d.ts.map +1 -1
- package/dist/portal.js +5 -2
- package/dist/portal.js.map +1 -1
- package/dist/progressive-blur.d.ts +7 -0
- package/dist/progressive-blur.d.ts.map +1 -0
- package/dist/progressive-blur.js +20 -0
- package/dist/progressive-blur.js.map +1 -0
- package/dist/rating.d.ts +19 -0
- package/dist/rating.d.ts.map +1 -0
- package/dist/rating.js +34 -0
- package/dist/rating.js.map +1 -0
- package/dist/selection.d.ts +4 -0
- package/dist/selection.d.ts.map +1 -1
- package/dist/selection.js +45 -3
- package/dist/selection.js.map +1 -1
- package/dist/styles.css +41 -4
- package/dist/styles.layered.css +41 -4
- package/dist/task-list.d.ts +6 -1
- package/dist/task-list.d.ts.map +1 -1
- package/dist/task-list.js +8 -3
- package/dist/task-list.js.map +1 -1
- package/dist/text-annotation.d.ts +10 -0
- package/dist/text-annotation.d.ts.map +1 -0
- package/dist/text-annotation.js +107 -0
- package/dist/text-annotation.js.map +1 -0
- package/package.json +33 -3
|
@@ -0,0 +1,10 @@
|
|
|
1
|
+
import { type TextAnnotationAction } from '@hjmds/design-contracts/text-annotation';
|
|
2
|
+
/** Internal renderer while Native range measurement and the public API are
|
|
3
|
+
* being developed. Kept out of package exports until both paths are reviewable.
|
|
4
|
+
*/
|
|
5
|
+
export type TextAnnotationProps = Readonly<{
|
|
6
|
+
children: string;
|
|
7
|
+
action?: TextAnnotationAction;
|
|
8
|
+
}>;
|
|
9
|
+
export declare function TextAnnotation({ children, action }: TextAnnotationProps): import("react").JSX.Element;
|
|
10
|
+
//# sourceMappingURL=text-annotation.d.ts.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"text-annotation.d.ts","sourceRoot":"","sources":["../src/text-annotation.tsx"],"names":[],"mappings":"AACA,OAAO,EAA+D,KAAK,oBAAoB,EAA2B,MAAM,yCAAyC,CAAC;AAI1K;;GAEG;AACH,MAAM,MAAM,mBAAmB,GAAG,QAAQ,CAAC;IACzC,QAAQ,EAAE,MAAM,CAAC;IACjB,MAAM,CAAC,EAAE,oBAAoB,CAAC;CAC/B,CAAC,CAAC;AAEH,wBAAgB,cAAc,CAAC,EAAE,QAAQ,EAAE,MAAoB,EAAE,EAAE,mBAAmB,+BAmGrF"}
|
|
@@ -0,0 +1,107 @@
|
|
|
1
|
+
import { jsx as _jsx, jsxs as _jsxs } from "react/jsx-runtime";
|
|
2
|
+
import { motion } from '@hjmds/design-contracts/foundations';
|
|
3
|
+
import { mergeTextAnnotationFragments, resolveTextAnnotationGeometry } from '@hjmds/design-contracts/text-annotation';
|
|
4
|
+
import { useLayoutEffect, useRef, useState } from 'react';
|
|
5
|
+
import { useHjmTheme } from './provider.js';
|
|
6
|
+
export function TextAnnotation({ children, action = 'highlight' }) {
|
|
7
|
+
const { environment } = useHjmTheme();
|
|
8
|
+
const textRef = useRef(null);
|
|
9
|
+
const anchorRef = useRef(null);
|
|
10
|
+
const svgRef = useRef(null);
|
|
11
|
+
const played = useRef(null);
|
|
12
|
+
const measured = useRef('');
|
|
13
|
+
const [measurement, setMeasurement] = useState({ content: children, lines: [] });
|
|
14
|
+
// A new string must not briefly receive paths measured for the old string.
|
|
15
|
+
const lines = measurement.content === children ? measurement.lines : [];
|
|
16
|
+
const geometry = resolveTextAnnotationGeometry(lines, action);
|
|
17
|
+
const key = `${action}:${children}`;
|
|
18
|
+
useLayoutEffect(() => {
|
|
19
|
+
const text = textRef.current, anchor = anchorRef.current;
|
|
20
|
+
if (!text || !anchor)
|
|
21
|
+
return;
|
|
22
|
+
let frame = 0, alive = true;
|
|
23
|
+
const measure = () => {
|
|
24
|
+
frame = 0;
|
|
25
|
+
if (!alive)
|
|
26
|
+
return;
|
|
27
|
+
const origin = anchor.getBoundingClientRect();
|
|
28
|
+
const range = document.createRange();
|
|
29
|
+
range.selectNodeContents(text);
|
|
30
|
+
// Range rectangles are actual shaped fragments, including mixed-direction
|
|
31
|
+
// runs. An inline-block or character-width estimate changes line wrapping.
|
|
32
|
+
const fragments = Array.from(range.getClientRects()).filter(rect => rect.width > 0 && rect.height > 0);
|
|
33
|
+
const bands = [];
|
|
34
|
+
const next = mergeTextAnnotationFragments(fragments.map(rect => {
|
|
35
|
+
// Chromium splits a mixed Arabic/English line into adjacent bidi runs.
|
|
36
|
+
// Separate outlines create interior seams (QA highlighter §11). Merge
|
|
37
|
+
// only measured matching vertical bands; guessing by character order or
|
|
38
|
+
// overlap alone could merge distinct lines with a tight line-height.
|
|
39
|
+
let lineIndex = bands.findIndex(band => Math.abs(band.top - rect.top) < 0.01 && Math.abs(band.height - rect.height) < 0.01);
|
|
40
|
+
if (lineIndex < 0) {
|
|
41
|
+
lineIndex = bands.length;
|
|
42
|
+
bands.push({ top: rect.top, height: rect.height });
|
|
43
|
+
}
|
|
44
|
+
return { x: rect.left - origin.left, y: rect.top - origin.top, width: rect.width, height: rect.height, lineIndex };
|
|
45
|
+
}));
|
|
46
|
+
const signature = JSON.stringify([children, next]);
|
|
47
|
+
if (measured.current !== signature) {
|
|
48
|
+
measured.current = signature;
|
|
49
|
+
setMeasurement({ content: children, lines: next });
|
|
50
|
+
}
|
|
51
|
+
};
|
|
52
|
+
const schedule = () => { if (!frame)
|
|
53
|
+
frame = requestAnimationFrame(measure); };
|
|
54
|
+
measure();
|
|
55
|
+
const observer = new ResizeObserver(schedule);
|
|
56
|
+
const mutation = new MutationObserver(records => {
|
|
57
|
+
if (records.some(record => !anchor.contains(record.target)))
|
|
58
|
+
schedule();
|
|
59
|
+
});
|
|
60
|
+
// Inline fragments themselves may not emit ResizeObserver notifications.
|
|
61
|
+
// Observe ancestors too: a preceding sibling can move the first fragment
|
|
62
|
+
// without changing its text or font.
|
|
63
|
+
for (let element = text; element; element = element.parentElement) {
|
|
64
|
+
observer.observe(element);
|
|
65
|
+
mutation.observe(element, { attributes: true, attributeFilter: ['style', 'class', 'dir'] });
|
|
66
|
+
}
|
|
67
|
+
const paragraph = text.closest('p, h1, h2, h3, h4, h5, h6, li') ?? text.parentElement?.parentElement;
|
|
68
|
+
// Ignore our SVG's mutations; measuring it would create an observer loop.
|
|
69
|
+
if (paragraph)
|
|
70
|
+
mutation.observe(paragraph, { childList: true, characterData: true, subtree: true, attributes: true, attributeFilter: ['style', 'class', 'dir'] });
|
|
71
|
+
document.fonts.addEventListener('loadingdone', schedule);
|
|
72
|
+
void document.fonts.ready.then(() => { if (alive)
|
|
73
|
+
schedule(); });
|
|
74
|
+
window.addEventListener('resize', schedule);
|
|
75
|
+
return () => { alive = false; cancelAnimationFrame(frame); observer.disconnect(); mutation.disconnect(); document.fonts.removeEventListener('loadingdone', schedule); window.removeEventListener('resize', schedule); };
|
|
76
|
+
}, [children, environment.textScale, environment.direction]);
|
|
77
|
+
useLayoutEffect(() => {
|
|
78
|
+
const svg = svgRef.current;
|
|
79
|
+
if (!svg || !geometry.paths.length || played.current === key)
|
|
80
|
+
return;
|
|
81
|
+
played.current = key;
|
|
82
|
+
// Geometry updates are not new content. Do not replay entry motion on every
|
|
83
|
+
// ResizeObserver delivery, unlike the upstream hide/show-on-body-resize path.
|
|
84
|
+
if (environment.reducedMotion || document.hidden)
|
|
85
|
+
return;
|
|
86
|
+
const animations = [];
|
|
87
|
+
for (const path of svg.querySelectorAll('path')) {
|
|
88
|
+
if (action === 'highlight') {
|
|
89
|
+
const start = environment.direction === 'rtl' ? 'inset(0 0 0 100%)' : 'inset(0 100% 0 0)';
|
|
90
|
+
animations.push(path.animate([{ clipPath: start }, { clipPath: 'inset(0 0 0 0)' }], { duration: motion.slow, easing: 'ease-out' }));
|
|
91
|
+
}
|
|
92
|
+
else {
|
|
93
|
+
const length = path.getTotalLength();
|
|
94
|
+
animations.push(path.animate([{ strokeDasharray: `${length}`, strokeDashoffset: length }, { strokeDasharray: `${length}`, strokeDashoffset: 0 }], { duration: motion.slow, easing: 'ease-out' }));
|
|
95
|
+
}
|
|
96
|
+
}
|
|
97
|
+
const stop = () => { for (const animation of animations)
|
|
98
|
+
animation.cancel(); };
|
|
99
|
+
const visibility = () => { if (document.hidden)
|
|
100
|
+
stop(); };
|
|
101
|
+
document.addEventListener('visibilitychange', visibility);
|
|
102
|
+
return () => { stop(); document.removeEventListener('visibilitychange', visibility); };
|
|
103
|
+
}, [key, lines, action, environment.reducedMotion, environment.direction, geometry.paths.length]);
|
|
104
|
+
const bounds = geometry.bounds;
|
|
105
|
+
return _jsxs("span", { "data-hjm-text-annotation": action, style: { display: 'inline', position: 'relative', isolation: 'isolate' }, children: [_jsx("span", { ref: anchorRef, "aria-hidden": "true", style: { position: 'absolute', left: 0, top: 0, width: 0, height: 0, pointerEvents: 'none' }, children: bounds ? _jsx("svg", { ref: svgRef, "aria-hidden": "true", focusable: "false", width: bounds.width, height: bounds.height, viewBox: `${bounds.x} ${bounds.y} ${bounds.width} ${bounds.height}`, style: { position: 'absolute', left: bounds.x, top: bounds.y, overflow: 'visible', pointerEvents: 'none' }, children: geometry.paths.map((path, index) => _jsx("path", { d: path.d, "data-line": path.lineIndex, fill: path.paint === 'fill' ? 'var(--hjm-color-primary)' : 'none', fillOpacity: path.paint === 'fill' ? 0.2 : 1, stroke: path.paint === 'stroke' ? 'var(--hjm-color-content-brand)' : 'none', strokeWidth: path.strokeWidth, strokeLinecap: "round", strokeLinejoin: "round" }, index)) }) : null }), _jsx("span", { ref: textRef, "data-hjm-annotation-text": "", style: { position: 'relative' }, children: children })] });
|
|
106
|
+
}
|
|
107
|
+
//# sourceMappingURL=text-annotation.js.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"text-annotation.js","sourceRoot":"","sources":["../src/text-annotation.tsx"],"names":[],"mappings":"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","sourcesContent":["import { motion } from '@hjmds/design-contracts/foundations';\nimport { mergeTextAnnotationFragments, resolveTextAnnotationGeometry, type TextAnnotationAction, type TextAnnotationRect } from '@hjmds/design-contracts/text-annotation';\nimport { useLayoutEffect, useRef, useState } from 'react';\nimport { useHjmTheme } from './provider.js';\n\n/** Internal renderer while Native range measurement and the public API are\n * being developed. Kept out of package exports until both paths are reviewable.\n */\nexport type TextAnnotationProps = Readonly<{\n children: string;\n action?: TextAnnotationAction;\n}>;\n\nexport function TextAnnotation({ children, action = 'highlight' }: TextAnnotationProps) {\n const { environment } = useHjmTheme();\n const textRef = useRef<HTMLSpanElement>(null);\n const anchorRef = useRef<HTMLSpanElement>(null);\n const svgRef = useRef<SVGSVGElement>(null);\n const played = useRef<string | null>(null);\n const measured = useRef('');\n const [measurement, setMeasurement] = useState<{ content: string; lines: readonly TextAnnotationRect[] }>({ content: children, lines: [] });\n // A new string must not briefly receive paths measured for the old string.\n const lines = measurement.content === children ? measurement.lines : [];\n const geometry = resolveTextAnnotationGeometry(lines, action);\n const key = `${action}:${children}`;\n\n useLayoutEffect(() => {\n const text = textRef.current, anchor = anchorRef.current;\n if (!text || !anchor) return;\n let frame = 0, alive = true;\n const measure = () => {\n frame = 0;\n if (!alive) return;\n const origin = anchor.getBoundingClientRect();\n const range = document.createRange();\n range.selectNodeContents(text);\n // Range rectangles are actual shaped fragments, including mixed-direction\n // runs. An inline-block or character-width estimate changes line wrapping.\n const fragments = Array.from(range.getClientRects()).filter(rect => rect.width > 0 && rect.height > 0);\n const bands: { top: number; height: number }[] = [];\n const next = mergeTextAnnotationFragments(fragments.map(rect => {\n // Chromium splits a mixed Arabic/English line into adjacent bidi runs.\n // Separate outlines create interior seams (QA highlighter §11). Merge\n // only measured matching vertical bands; guessing by character order or\n // overlap alone could merge distinct lines with a tight line-height.\n let lineIndex = bands.findIndex(band => Math.abs(band.top - rect.top) < 0.01 && Math.abs(band.height - rect.height) < 0.01);\n if (lineIndex < 0) { lineIndex = bands.length; bands.push({ top: rect.top, height: rect.height }); }\n return { x: rect.left - origin.left, y: rect.top - origin.top, width: rect.width, height: rect.height, lineIndex };\n }));\n const signature = JSON.stringify([children, next]);\n if (measured.current !== signature) {\n measured.current = signature;\n setMeasurement({ content: children, lines: next });\n }\n };\n const schedule = () => { if (!frame) frame = requestAnimationFrame(measure); };\n measure();\n const observer = new ResizeObserver(schedule);\n const mutation = new MutationObserver(records => {\n if (records.some(record => !anchor.contains(record.target))) schedule();\n });\n // Inline fragments themselves may not emit ResizeObserver notifications.\n // Observe ancestors too: a preceding sibling can move the first fragment\n // without changing its text or font.\n for (let element: Element | null = text; element; element = element.parentElement) {\n observer.observe(element);\n mutation.observe(element, { attributes: true, attributeFilter: ['style', 'class', 'dir'] });\n }\n const paragraph = text.closest('p, h1, h2, h3, h4, h5, h6, li') ?? text.parentElement?.parentElement;\n // Ignore our SVG's mutations; measuring it would create an observer loop.\n if (paragraph) mutation.observe(paragraph, { childList: true, characterData: true, subtree: true, attributes: true, attributeFilter: ['style', 'class', 'dir'] });\n document.fonts.addEventListener('loadingdone', schedule);\n void document.fonts.ready.then(() => { if (alive) schedule(); });\n window.addEventListener('resize', schedule);\n return () => { alive = false; cancelAnimationFrame(frame); observer.disconnect(); mutation.disconnect(); document.fonts.removeEventListener('loadingdone', schedule); window.removeEventListener('resize', schedule); };\n }, [children, environment.textScale, environment.direction]);\n\n useLayoutEffect(() => {\n const svg = svgRef.current;\n if (!svg || !geometry.paths.length || played.current === key) return;\n played.current = key;\n // Geometry updates are not new content. Do not replay entry motion on every\n // ResizeObserver delivery, unlike the upstream hide/show-on-body-resize path.\n if (environment.reducedMotion || document.hidden) return;\n const animations: Animation[] = [];\n for (const path of svg.querySelectorAll('path')) {\n if (action === 'highlight') {\n const start = environment.direction === 'rtl' ? 'inset(0 0 0 100%)' : 'inset(0 100% 0 0)';\n animations.push(path.animate([{ clipPath: start }, { clipPath: 'inset(0 0 0 0)' }], { duration: motion.slow, easing: 'ease-out' }));\n } else {\n const length = path.getTotalLength();\n animations.push(path.animate([{ strokeDasharray: `${length}`, strokeDashoffset: length }, { strokeDasharray: `${length}`, strokeDashoffset: 0 }], { duration: motion.slow, easing: 'ease-out' }));\n }\n }\n const stop = () => { for (const animation of animations) animation.cancel(); };\n const visibility = () => { if (document.hidden) stop(); };\n document.addEventListener('visibilitychange', visibility);\n return () => { stop(); document.removeEventListener('visibilitychange', visibility); };\n }, [key, lines, action, environment.reducedMotion, environment.direction, geometry.paths.length]);\n\n const bounds = geometry.bounds;\n return <span data-hjm-text-annotation={action} style={{ display: 'inline', position: 'relative', isolation: 'isolate' }}>\n <span ref={anchorRef} aria-hidden=\"true\" style={{ position: 'absolute', left: 0, top: 0, width: 0, height: 0, pointerEvents: 'none' }}>\n {bounds ? <svg ref={svgRef} aria-hidden=\"true\" focusable=\"false\" width={bounds.width} height={bounds.height} viewBox={`${bounds.x} ${bounds.y} ${bounds.width} ${bounds.height}`} style={{ position: 'absolute', left: bounds.x, top: bounds.y, overflow: 'visible', pointerEvents: 'none' }}>\n {/* Marker ink stays behind unchanged foreground text. The experimental\n 20% wash avoids replacing its semantic foreground with a brand color;\n product-palette contrast still needs validation before promotion. */}\n {geometry.paths.map((path, index) => <path key={index} d={path.d} data-line={path.lineIndex} fill={path.paint === 'fill' ? 'var(--hjm-color-primary)' : 'none'} fillOpacity={path.paint === 'fill' ? 0.2 : 1} stroke={path.paint === 'stroke' ? 'var(--hjm-color-content-brand)' : 'none'} strokeWidth={path.strokeWidth} strokeLinecap=\"round\" strokeLinejoin=\"round\" />)}\n </svg> : null}\n </span>\n <span ref={textRef} data-hjm-annotation-text=\"\" style={{ position: 'relative' }}>{children}</span>\n </span>;\n}\n"]}
|
package/package.json
CHANGED
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
{
|
|
2
2
|
"name": "@hjmds/react",
|
|
3
|
-
"version": "1.
|
|
3
|
+
"version": "1.14.0",
|
|
4
4
|
"description": "Accessible React 19 renderers for HJM design contracts.",
|
|
5
5
|
"license": "MIT",
|
|
6
6
|
"publishConfig": {
|
|
@@ -356,6 +356,16 @@
|
|
|
356
356
|
"import": "./dist/content-transition.js",
|
|
357
357
|
"default": "./dist/content-transition.js"
|
|
358
358
|
},
|
|
359
|
+
"./rating": {
|
|
360
|
+
"types": "./dist/rating.d.ts",
|
|
361
|
+
"import": "./dist/rating.js",
|
|
362
|
+
"default": "./dist/rating.js"
|
|
363
|
+
},
|
|
364
|
+
"./image-comparison": {
|
|
365
|
+
"types": "./dist/image-comparison.d.ts",
|
|
366
|
+
"import": "./dist/image-comparison.js",
|
|
367
|
+
"default": "./dist/image-comparison.js"
|
|
368
|
+
},
|
|
359
369
|
"./carousel-motion": {
|
|
360
370
|
"types": "./dist/carousel-motion.d.ts",
|
|
361
371
|
"import": "./dist/carousel-motion.js",
|
|
@@ -472,6 +482,26 @@
|
|
|
472
482
|
"types": "./dist/saved-items.d.ts",
|
|
473
483
|
"import": "./dist/saved-items.js",
|
|
474
484
|
"default": "./dist/saved-items.js"
|
|
485
|
+
},
|
|
486
|
+
"./progressive-blur": {
|
|
487
|
+
"types": "./dist/progressive-blur.d.ts",
|
|
488
|
+
"import": "./dist/progressive-blur.js",
|
|
489
|
+
"default": "./dist/progressive-blur.js"
|
|
490
|
+
},
|
|
491
|
+
"./date-entry": {
|
|
492
|
+
"types": "./dist/date-entry.d.ts",
|
|
493
|
+
"import": "./dist/date-entry.js",
|
|
494
|
+
"default": "./dist/date-entry.js"
|
|
495
|
+
},
|
|
496
|
+
"./field-group": {
|
|
497
|
+
"types": "./dist/field-group.d.ts",
|
|
498
|
+
"import": "./dist/field-group.js",
|
|
499
|
+
"default": "./dist/field-group.js"
|
|
500
|
+
},
|
|
501
|
+
"./document-resource": {
|
|
502
|
+
"types": "./dist/document-resource.d.ts",
|
|
503
|
+
"import": "./dist/document-resource.js",
|
|
504
|
+
"default": "./dist/document-resource.js"
|
|
475
505
|
}
|
|
476
506
|
},
|
|
477
507
|
"files": [
|
|
@@ -481,7 +511,7 @@
|
|
|
481
511
|
"THIRD_PARTY_NOTICES.md"
|
|
482
512
|
],
|
|
483
513
|
"peerDependencies": {
|
|
484
|
-
"@hjmds/design-contracts": ">=1.
|
|
514
|
+
"@hjmds/design-contracts": ">=1.14.0 <1.15.0",
|
|
485
515
|
"react": ">=19.0.0",
|
|
486
516
|
"react-dom": ">=19.0.0",
|
|
487
517
|
"@number-flow/react": "0.6.2",
|
|
@@ -518,7 +548,7 @@
|
|
|
518
548
|
"blobatar": "2.7.0",
|
|
519
549
|
"@blobatar/react": "2.7.0",
|
|
520
550
|
"lucide-react": "1.49.0",
|
|
521
|
-
"@hjmds/design-contracts": "1.
|
|
551
|
+
"@hjmds/design-contracts": "1.14.0"
|
|
522
552
|
},
|
|
523
553
|
"peerDependenciesMeta": {
|
|
524
554
|
"@number-flow/react": {
|