@santi020k/lumen-react 3.0.0 → 4.0.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.
Files changed (145) hide show
  1. package/README.md +666 -13
  2. package/dist/ai-surfaces.d.ts +49 -0
  3. package/dist/ai-surfaces.d.ts.map +1 -0
  4. package/dist/ai-surfaces.js +88 -0
  5. package/dist/amount-field.d.ts +11 -0
  6. package/dist/amount-field.d.ts.map +1 -0
  7. package/dist/amount-field.js +37 -0
  8. package/dist/attachments.d.ts +17 -0
  9. package/dist/attachments.d.ts.map +1 -0
  10. package/dist/attachments.js +23 -0
  11. package/dist/bullet-chart.d.ts +14 -0
  12. package/dist/bullet-chart.d.ts.map +1 -0
  13. package/dist/bullet-chart.js +22 -0
  14. package/dist/change-summary.d.ts +14 -0
  15. package/dist/change-summary.d.ts.map +1 -0
  16. package/dist/change-summary.js +4 -0
  17. package/dist/chart-inspection.d.ts +10 -0
  18. package/dist/chart-inspection.d.ts.map +1 -0
  19. package/dist/chart-inspection.js +11 -0
  20. package/dist/chart-interaction.d.ts +17 -0
  21. package/dist/chart-interaction.d.ts.map +1 -0
  22. package/dist/chart-interaction.js +50 -0
  23. package/dist/chart-label.d.ts +3 -0
  24. package/dist/chart-label.d.ts.map +1 -0
  25. package/dist/chart-label.js +1 -0
  26. package/dist/chart-recipes.d.ts +8 -0
  27. package/dist/chart-recipes.d.ts.map +1 -1
  28. package/dist/chart-recipes.js +35 -0
  29. package/dist/combobox.d.ts +9 -0
  30. package/dist/combobox.d.ts.map +1 -0
  31. package/dist/combobox.js +137 -0
  32. package/dist/comparison-chart.d.ts +13 -0
  33. package/dist/comparison-chart.d.ts.map +1 -0
  34. package/dist/comparison-chart.js +18 -0
  35. package/dist/components.d.ts +106 -70
  36. package/dist/components.d.ts.map +1 -1
  37. package/dist/components.js +4 -1947
  38. package/dist/dashboard.d.ts +20 -0
  39. package/dist/dashboard.d.ts.map +1 -0
  40. package/dist/dashboard.js +19 -0
  41. package/dist/data-table-range-model.d.ts +8 -0
  42. package/dist/data-table-range-model.d.ts.map +1 -0
  43. package/dist/data-table-range-model.js +31 -0
  44. package/dist/data-table-range.d.ts +17 -0
  45. package/dist/data-table-range.d.ts.map +1 -0
  46. package/dist/data-table-range.js +8 -0
  47. package/dist/data-table-saved-views.d.ts +30 -0
  48. package/dist/data-table-saved-views.d.ts.map +1 -0
  49. package/dist/data-table-saved-views.js +49 -0
  50. package/dist/data-table-selection-model.d.ts +23 -0
  51. package/dist/data-table-selection-model.d.ts.map +1 -0
  52. package/dist/data-table-selection-model.js +36 -0
  53. package/dist/data-table-selection.d.ts +11 -0
  54. package/dist/data-table-selection.d.ts.map +1 -0
  55. package/dist/data-table-selection.js +10 -0
  56. package/dist/data-table-state.d.ts +6 -0
  57. package/dist/data-table-state.d.ts.map +1 -0
  58. package/dist/data-table-state.js +38 -0
  59. package/dist/data-table-view.d.ts +88 -0
  60. package/dist/data-table-view.d.ts.map +1 -0
  61. package/dist/data-table-view.js +1 -0
  62. package/dist/data-table.d.ts +60 -0
  63. package/dist/data-table.d.ts.map +1 -0
  64. package/dist/data-table.js +1 -0
  65. package/dist/date-range-calendar.d.ts +29 -0
  66. package/dist/date-range-calendar.d.ts.map +1 -0
  67. package/dist/date-range-calendar.js +69 -0
  68. package/dist/date-range-input.d.ts +25 -0
  69. package/dist/date-range-input.d.ts.map +1 -0
  70. package/dist/date-range-input.js +195 -0
  71. package/dist/device-frame.d.ts +13 -0
  72. package/dist/device-frame.d.ts.map +1 -0
  73. package/dist/device-frame.js +23 -0
  74. package/dist/dialog-lifecycle.d.ts +3 -0
  75. package/dist/dialog-lifecycle.d.ts.map +1 -0
  76. package/dist/dialog-lifecycle.js +70 -0
  77. package/dist/expanded-charts.d.ts +26 -0
  78. package/dist/expanded-charts.d.ts.map +1 -0
  79. package/dist/expanded-charts.js +46 -0
  80. package/dist/floating-panel.d.ts +11 -0
  81. package/dist/floating-panel.d.ts.map +1 -0
  82. package/dist/floating-panel.js +1 -0
  83. package/dist/form-workflow.d.ts +77 -0
  84. package/dist/form-workflow.d.ts.map +1 -0
  85. package/dist/form-workflow.js +337 -0
  86. package/dist/hooks.d.ts +24 -21
  87. package/dist/hooks.d.ts.map +1 -1
  88. package/dist/hooks.js +1 -2468
  89. package/dist/image-comparison.d.ts +20 -0
  90. package/dist/image-comparison.d.ts.map +1 -0
  91. package/dist/image-comparison.js +55 -0
  92. package/dist/index.d.ts +25 -1
  93. package/dist/index.d.ts.map +1 -1
  94. package/dist/index.js +24 -0
  95. package/dist/interval-charts.d.ts +21 -0
  96. package/dist/interval-charts.d.ts.map +1 -0
  97. package/dist/interval-charts.js +23 -0
  98. package/dist/media-selection.d.ts +18 -0
  99. package/dist/media-selection.d.ts.map +1 -0
  100. package/dist/media-selection.js +12 -0
  101. package/dist/media-viewport.d.ts +16 -0
  102. package/dist/media-viewport.d.ts.map +1 -0
  103. package/dist/media-viewport.js +37 -0
  104. package/dist/motion.d.ts +597 -0
  105. package/dist/motion.d.ts.map +1 -0
  106. package/dist/motion.js +22 -0
  107. package/dist/review-workflow.d.ts +32 -0
  108. package/dist/review-workflow.d.ts.map +1 -0
  109. package/dist/review-workflow.js +76 -0
  110. package/dist/rich-text-editor.d.ts +21 -0
  111. package/dist/rich-text-editor.d.ts.map +1 -0
  112. package/dist/rich-text-editor.js +143 -0
  113. package/dist/select-form.d.ts +3 -0
  114. package/dist/select-form.d.ts.map +1 -0
  115. package/dist/select-form.js +1 -0
  116. package/dist/server-components.d.ts +24 -4
  117. package/dist/server-components.d.ts.map +1 -1
  118. package/dist/server-components.js +11 -3
  119. package/dist/server.d.ts +1 -0
  120. package/dist/server.d.ts.map +1 -1
  121. package/dist/server.js +1 -0
  122. package/dist/toast-context.d.ts +4 -0
  123. package/dist/toast-context.d.ts.map +1 -0
  124. package/dist/toast-context.js +10 -0
  125. package/dist/toast-provider.d.ts +3 -0
  126. package/dist/toast-provider.d.ts.map +1 -0
  127. package/dist/toast-provider.js +3 -0
  128. package/dist/use-copy-feedback.d.ts +17 -0
  129. package/dist/use-copy-feedback.d.ts.map +1 -0
  130. package/dist/use-copy-feedback.js +54 -0
  131. package/dist/virtual-list-data.d.ts +13 -0
  132. package/dist/virtual-list-data.d.ts.map +1 -0
  133. package/dist/virtual-list-data.js +87 -0
  134. package/dist/virtual-list.d.ts +14 -0
  135. package/dist/virtual-list.d.ts.map +1 -0
  136. package/dist/virtual-list.js +24 -0
  137. package/dist/visual-interactions.d.ts +16 -0
  138. package/dist/visual-interactions.d.ts.map +1 -0
  139. package/dist/visual-interactions.js +30 -0
  140. package/dist/world-map.d.ts +26 -0
  141. package/dist/world-map.d.ts.map +1 -0
  142. package/dist/world-map.js +81 -0
  143. package/package.json +99 -11
  144. package/styles/critical.css +634 -61
  145. package/styles/data-table-view.css +36 -0
@@ -0,0 +1,87 @@
1
+ 'use client';
2
+ import { jsx as _jsx } from "react/jsx-runtime";
3
+ import { useCallback, useLayoutEffect, useMemo, useRef, useState, useSyncExternalStore } from 'react';
4
+ import { composeClassName, getLumenVirtualWindow, observeLumenVirtualWindow } from '@santi020k/lumen-core';
5
+ const getRenderedIndexes = (visible, focusedKey, indexesByKey, count) => {
6
+ const focusedIndex = focusedKey === null ? -1 : indexesByKey.get(focusedKey) ?? -1;
7
+ const indexes = new Set(visible);
8
+ if (focusedIndex >= 0) {
9
+ const end = Math.min(count - 1, focusedIndex + 1);
10
+ for (let index = Math.max(0, focusedIndex - 1); index <= end; index += 1)
11
+ indexes.add(index);
12
+ }
13
+ return [...indexes].sort((first, second) => first - second);
14
+ };
15
+ export const VirtualListData = ({ className, getKey, glass = false, items, itemSize = 44, overscan = 4, renderItem, ref, role = 'list', style, tabIndex = 0, onFocusCapture, onBlurCapture, ...props }) => {
16
+ const rootRef = useRef(null);
17
+ const focusedElementRef = useRef(null);
18
+ const [focusedKey, setFocusedKey] = useState(null);
19
+ const entries = useMemo(() => {
20
+ const keys = new Set();
21
+ return Array.from(items, (item, index) => {
22
+ const key = String(getKey(item, index));
23
+ if (keys.has(key))
24
+ throw new Error(`VirtualList item keys must be unique: ${key}`);
25
+ keys.add(key);
26
+ return { item, key };
27
+ });
28
+ }, [getKey, items]);
29
+ const indexesByKey = useMemo(() => new Map(entries.map((entry, index) => [entry.key, index])), [entries]);
30
+ const store = useMemo(() => {
31
+ const initial = getLumenVirtualWindow(0, 0, items.length, itemSize, overscan);
32
+ return { initial, snapshot: initial };
33
+ }, [itemSize, items.length, overscan]);
34
+ const setRootRef = useCallback((element) => {
35
+ rootRef.current = element;
36
+ if (typeof ref === 'function')
37
+ ref(element);
38
+ else if (ref)
39
+ ref.current = element;
40
+ }, [ref]);
41
+ const subscribe = useCallback((notify) => {
42
+ const root = rootRef.current;
43
+ if (!root)
44
+ return () => undefined;
45
+ const observer = observeLumenVirtualWindow(root, {
46
+ itemCount: items.length,
47
+ itemSize,
48
+ overscan,
49
+ onChange: next => {
50
+ store.snapshot = next;
51
+ notify();
52
+ }
53
+ });
54
+ return observer.destroy;
55
+ }, [itemSize, items.length, overscan, store]);
56
+ const window = useSyncExternalStore(subscribe, () => store.snapshot, () => store.initial);
57
+ const indexes = getRenderedIndexes(window.indexes, focusedKey, indexesByKey, items.length);
58
+ // Browser DOM moves can drop focus during a keyed reorder; restore the retained control afterward.
59
+ useLayoutEffect(() => {
60
+ const root = rootRef.current;
61
+ const focused = focusedElementRef.current;
62
+ if (!root || !focused || root.ownerDocument.activeElement !== root.ownerDocument.body)
63
+ return;
64
+ if (focused.isConnected && root.contains(focused))
65
+ focused.focus({ preventScroll: true });
66
+ else
67
+ root.focus({ preventScroll: true });
68
+ }, [entries, window]);
69
+ return (_jsx("div", { ...props, className: composeClassName('ui-virtual-list', glass && 'ui-virtual-list--glass', glass === 'subtle' && 'ui-glass-subtle', glass === 'strong' && 'ui-glass-strong', className), "data-ui-virtual-list": true, "data-ui-virtual-list-mode": "data", onFocusCapture: event => {
70
+ onFocusCapture?.(event);
71
+ const target = event.target;
72
+ const row = target.closest('[data-ui-virtual-list-key]');
73
+ focusedElementRef.current = row ? target : null;
74
+ setFocusedKey(row?.dataset.uiVirtualListKey ?? null);
75
+ }, onBlurCapture: event => {
76
+ onBlurCapture?.(event);
77
+ if (event.currentTarget.contains(event.relatedTarget))
78
+ return;
79
+ focusedElementRef.current = null;
80
+ setFocusedKey(null);
81
+ }, ref: setRootRef, role: role, style: style, tabIndex: tabIndex, children: _jsx("div", { "data-ui-virtual-list-content": true, style: { height: window.totalSize, position: 'relative' }, children: indexes.map(index => {
82
+ const entry = entries[index];
83
+ if (!entry)
84
+ return null;
85
+ return (_jsx("div", { "aria-posinset": role === 'list' ? index + 1 : undefined, "aria-setsize": role === 'list' ? items.length : undefined, "data-ui-virtual-list-index": index, "data-ui-virtual-list-key": entry.key, role: role === 'list' ? 'listitem' : undefined, style: { boxSizing: 'border-box', height: window.itemSize, insetInline: 0, position: 'absolute', top: index * window.itemSize }, children: renderItem(entry.item, index) }, entry.key));
86
+ }) }) }));
87
+ };
@@ -0,0 +1,14 @@
1
+ import type { ComponentPropsWithRef } from 'react';
2
+ import type { LumenGlassProp } from './components.js';
3
+ import { type VirtualListDataProps } from './virtual-list-data.js';
4
+ export interface VirtualListProps extends ComponentPropsWithRef<'div'> {
5
+ glass?: LumenGlassProp;
6
+ items?: never;
7
+ getKey?: never;
8
+ renderItem?: never;
9
+ itemSize?: number | string;
10
+ overscan?: number | string;
11
+ }
12
+ export declare const VirtualList: <T>(props: VirtualListProps | VirtualListDataProps<T>) => import("react").JSX.Element;
13
+ export type { VirtualListDataProps } from './virtual-list-data.js';
14
+ //# sourceMappingURL=virtual-list.d.ts.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"virtual-list.d.ts","sourceRoot":"","sources":["../src/virtual-list.tsx"],"names":[],"mappings":"AAEA,OAAO,KAAK,EAAE,qBAAqB,EAAE,MAAM,OAAO,CAAA;AAKlD,OAAO,KAAK,EAAE,cAAc,EAAE,MAAM,iBAAiB,CAAA;AACrD,OAAO,EAAmB,KAAK,oBAAoB,EAAE,MAAM,wBAAwB,CAAA;AAEnF,MAAM,WAAW,gBAAiB,SAAQ,qBAAqB,CAAC,KAAK,CAAC;IACpE,KAAK,CAAC,EAAE,cAAc,CAAA;IACtB,KAAK,CAAC,EAAE,KAAK,CAAA;IACb,MAAM,CAAC,EAAE,KAAK,CAAA;IACd,UAAU,CAAC,EAAE,KAAK,CAAA;IAClB,QAAQ,CAAC,EAAE,MAAM,GAAG,MAAM,CAAA;IAC1B,QAAQ,CAAC,EAAE,MAAM,GAAG,MAAM,CAAA;CAC3B;AA6CD,eAAO,MAAM,WAAW,GAAI,CAAC,EAAG,OAAO,gBAAgB,GAAG,oBAAoB,CAAC,CAAC,CAAC,gCAEhF,CAAA;AAED,YAAY,EAAE,oBAAoB,EAAE,MAAM,wBAAwB,CAAA"}
@@ -0,0 +1,24 @@
1
+ 'use client';
2
+ import { jsx as _jsx } from "react/jsx-runtime";
3
+ import { useCallback, useEffect, useRef } from 'react';
4
+ import { composeClassName, createLumenVirtualListController } from '@santi020k/lumen-core';
5
+ import { VirtualListData } from './virtual-list-data.js';
6
+ const MountedVirtualList = ({ className, glass = false, itemSize, overscan, ref, tabIndex = 0, ...props }) => {
7
+ const rootRef = useRef(null);
8
+ const setRootRef = useCallback((element) => {
9
+ rootRef.current = element;
10
+ if (typeof ref === 'function')
11
+ ref(element);
12
+ else if (ref)
13
+ ref.current = element;
14
+ }, [ref]);
15
+ useEffect(() => {
16
+ const root = rootRef.current;
17
+ if (!root)
18
+ return;
19
+ const controller = createLumenVirtualListController(root);
20
+ return controller.destroy;
21
+ }, []);
22
+ return (_jsx("div", { className: composeClassName('ui-virtual-list', glass && 'ui-virtual-list--glass', glass === 'subtle' && 'ui-glass-subtle', glass === 'strong' && 'ui-glass-strong', className), "data-ui-item-size": itemSize, "data-ui-overscan": overscan, "data-ui-virtual-list": true, ref: setRootRef, tabIndex: tabIndex, ...props }));
23
+ };
24
+ export const VirtualList = (props) => (props.items !== undefined ? _jsx(VirtualListData, { ...props }) : _jsx(MountedVirtualList, { ...props }));
@@ -0,0 +1,16 @@
1
+ import type { ComponentPropsWithoutRef } from 'react';
2
+ import { type LumenVisualEffectVariant, type LumenWorkflowDuration } from '@santi020k/lumen-core';
3
+ export interface MotionGroupProps extends ComponentPropsWithoutRef<'div'> {
4
+ duration?: LumenWorkflowDuration;
5
+ enterExit?: boolean;
6
+ }
7
+ export declare const MotionGroup: ({ className, duration, enterExit, ...props }: MotionGroupProps) => import("react").JSX.Element;
8
+ export interface VisualEffectProps extends ComponentPropsWithoutRef<'div'> {
9
+ animated?: boolean;
10
+ intensity?: number;
11
+ variant?: LumenVisualEffectVariant;
12
+ }
13
+ export declare const VisualEffect: ({ animated, className, intensity, style, variant, ...props }: VisualEffectProps) => import("react").JSX.Element;
14
+ /** Wrap a chart to animate stable SVG marks without delaying accessible data. */
15
+ export declare const ChartMotion: ({ className, duration, ...props }: Omit<MotionGroupProps, "enterExit">) => import("react").JSX.Element;
16
+ //# sourceMappingURL=visual-interactions.d.ts.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"visual-interactions.d.ts","sourceRoot":"","sources":["../src/visual-interactions.tsx"],"names":[],"mappings":"AAEA,OAAO,KAAK,EAAE,wBAAwB,EAAiB,MAAM,OAAO,CAAA;AAGpE,OAAO,EAKL,KAAK,wBAAwB,EAC7B,KAAK,qBAAqB,EAE3B,MAAM,uBAAuB,CAAA;AAE9B,MAAM,WAAW,gBAAiB,SAAQ,wBAAwB,CAAC,KAAK,CAAC;IACvE,QAAQ,CAAC,EAAE,qBAAqB,CAAA;IAChC,SAAS,CAAC,EAAE,OAAO,CAAA;CACpB;AAED,eAAO,MAAM,WAAW,GAAI,8CAAkE,gBAAgB,gCAQ7G,CAAA;AAED,MAAM,WAAW,iBAAkB,SAAQ,wBAAwB,CAAC,KAAK,CAAC;IACxE,QAAQ,CAAC,EAAE,OAAO,CAAA;IAClB,SAAS,CAAC,EAAE,MAAM,CAAA;IAClB,OAAO,CAAC,EAAE,wBAAwB,CAAA;CACnC;AAID,eAAO,MAAM,YAAY,GAAI,8DAAqF,iBAAiB,gCAUlI,CAAA;AAED,iFAAiF;AACjF,eAAO,MAAM,WAAW,GAAI,mCAAgD,IAAI,CAAC,gBAAgB,EAAE,WAAW,CAAC,gCAQ9G,CAAA"}
@@ -0,0 +1,30 @@
1
+ 'use client';
2
+ import { jsx as _jsx } from "react/jsx-runtime";
3
+ import { useEffect, useRef } from 'react';
4
+ import { bindLumenChartMotion, bindLumenMotionGroup, composeClassName, createLumenSpotlightController, normalizeLumenEffectIntensity } from '@santi020k/lumen-core';
5
+ export const MotionGroup = ({ className, duration = 'standard', enterExit = true, ...props }) => {
6
+ const ref = useRef(null);
7
+ useEffect(() => {
8
+ if (ref.current)
9
+ return bindLumenMotionGroup(ref.current, { duration, enterExit });
10
+ }, [duration, enterExit]);
11
+ return _jsx("div", { ...props, ref: ref, className: composeClassName('ui-motion-group', className), "data-ui-motion-group": true });
12
+ };
13
+ export const VisualEffect = ({ animated = false, className, intensity = 0.5, style, variant = 'mesh', ...props }) => {
14
+ const ref = useRef(null);
15
+ useEffect(() => {
16
+ if (variant === 'spotlight' && ref.current)
17
+ return createLumenSpotlightController(ref.current);
18
+ }, [variant]);
19
+ const effectStyle = { ...style, '--ui-effect-intensity': normalizeLumenEffectIntensity(intensity) };
20
+ return _jsx("div", { ...props, ref: ref, className: composeClassName('ui-visual-effect', className), "data-ui-effect-animated": String(animated), "data-ui-visual-effect": variant, style: effectStyle });
21
+ };
22
+ /** Wrap a chart to animate stable SVG marks without delaying accessible data. */
23
+ export const ChartMotion = ({ className, duration = 'standard', ...props }) => {
24
+ const ref = useRef(null);
25
+ useEffect(() => {
26
+ if (ref.current)
27
+ return bindLumenChartMotion(ref.current, duration);
28
+ }, [duration]);
29
+ return _jsx("div", { ...props, ref: ref, className: className, "data-ui-chart-motion": true });
30
+ };
@@ -0,0 +1,26 @@
1
+ import type { ComponentPropsWithoutRef } from 'react';
2
+ import { type LumenWorldMapCountryGeometry, type LumenWorldMapMarker, type LumenWorldMapSelectDetail, type LumenWorldMapVariant } from '@santi020k/lumen-core/world-map';
3
+ import { type LumenWorldMapZoomLabels } from '@santi020k/lumen-core/world-map-zoom';
4
+ export interface WorldMapProps extends Omit<ComponentPropsWithoutRef<'figure'>, 'label'> {
5
+ initialView?: 'world' | 'highlighted';
6
+ zoomable?: boolean;
7
+ zoomLabels?: Partial<LumenWorldMapZoomLabels>;
8
+ animated?: boolean;
9
+ caption?: string;
10
+ countries: readonly LumenWorldMapCountryGeometry[];
11
+ defaultSelectedCountry?: string;
12
+ description?: string;
13
+ heading?: string;
14
+ highlightedCountries?: readonly string[];
15
+ interactive?: boolean;
16
+ label: string;
17
+ labels?: Readonly<Record<string, string>>;
18
+ listLabel?: string;
19
+ markers?: readonly LumenWorldMapMarker[];
20
+ onCountrySelect?: (detail: LumenWorldMapSelectDetail) => void;
21
+ onSelectedCountryChange?: (countryId: string) => void;
22
+ selectedCountry?: string;
23
+ variant?: LumenWorldMapVariant;
24
+ }
25
+ export declare const WorldMap: ({ animated, caption, className, countries: inputCountries, defaultSelectedCountry, description, heading, highlightedCountries, interactive, label, labels, listLabel, markers, onCountrySelect, onSelectedCountryChange, selectedCountry, variant, initialView, zoomable: zoomEnabled, zoomLabels, ...props }: WorldMapProps) => import("react").JSX.Element;
26
+ //# sourceMappingURL=world-map.d.ts.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"world-map.d.ts","sourceRoot":"","sources":["../src/world-map.tsx"],"names":[],"mappings":"AAEA,OAAO,KAAK,EAAE,wBAAwB,EAAa,MAAM,OAAO,CAAA;AAIhE,OAAO,EAIL,KAAK,4BAA4B,EACjC,KAAK,mBAAmB,EACxB,KAAK,yBAAyB,EAC9B,KAAK,oBAAoB,EAM1B,MAAM,iCAAiC,CAAA;AACxC,OAAO,EAEL,KAAK,uBAAuB,EAE7B,MAAM,sCAAsC,CAAA;AAsL7C,MAAM,WAAW,aAAc,SAAQ,IAAI,CAAC,wBAAwB,CAAC,QAAQ,CAAC,EAAE,OAAO,CAAC;IACtF,WAAW,CAAC,EAAE,OAAO,GAAG,aAAa,CAAA;IACrC,QAAQ,CAAC,EAAE,OAAO,CAAA;IAClB,UAAU,CAAC,EAAE,OAAO,CAAC,uBAAuB,CAAC,CAAA;IAC7C,QAAQ,CAAC,EAAE,OAAO,CAAA;IAClB,OAAO,CAAC,EAAE,MAAM,CAAA;IAChB,SAAS,EAAE,SAAS,4BAA4B,EAAE,CAAA;IAClD,sBAAsB,CAAC,EAAE,MAAM,CAAA;IAC/B,WAAW,CAAC,EAAE,MAAM,CAAA;IACpB,OAAO,CAAC,EAAE,MAAM,CAAA;IAChB,oBAAoB,CAAC,EAAE,SAAS,MAAM,EAAE,CAAA;IACxC,WAAW,CAAC,EAAE,OAAO,CAAA;IACrB,KAAK,EAAE,MAAM,CAAA;IACb,MAAM,CAAC,EAAE,QAAQ,CAAC,MAAM,CAAC,MAAM,EAAE,MAAM,CAAC,CAAC,CAAA;IACzC,SAAS,CAAC,EAAE,MAAM,CAAA;IAClB,OAAO,CAAC,EAAE,SAAS,mBAAmB,EAAE,CAAA;IACxC,eAAe,CAAC,EAAE,CAAC,MAAM,EAAE,yBAAyB,KAAK,IAAI,CAAA;IAC7D,uBAAuB,CAAC,EAAE,CAAC,SAAS,EAAE,MAAM,KAAK,IAAI,CAAA;IACrD,eAAe,CAAC,EAAE,MAAM,CAAA;IACxB,OAAO,CAAC,EAAE,oBAAoB,CAAA;CAC/B;AAED,eAAO,MAAM,QAAQ,GAAI,+SAsBtB,aAAa,gCAuHf,CAAA"}
@@ -0,0 +1,81 @@
1
+ 'use client';
2
+ import { jsx as _jsx, jsxs as _jsxs } from "react/jsx-runtime";
3
+ import { useEffect, useId, useMemo, useRef, useState } from 'react';
4
+ import { composeClassName } from '@santi020k/lumen-core/tokens';
5
+ import { createLumenWorldMapSelectDetail, findLumenWorldMapCountry, LUMEN_WORLD_MAP_VIEW_BOX, normalizeLumenWorldMapCountries, normalizeLumenWorldMapHighlightedCountries, normalizeLumenWorldMapMarkers, projectLumenWorldMapCoordinate, resolveLumenWorldMapCountryLabel } from '@santi020k/lumen-core/world-map';
6
+ import { initLumenWorldMapZoom, lumenWorldMapZoomLabels } from '@santi020k/lumen-core/world-map-zoom';
7
+ import { Button } from './components.js';
8
+ const ZoomControls = ({ enabled, labels }) => enabled && (_jsxs("div", { className: "ui-world-map__zoom-controls", children: [_jsx(Button, { "aria-label": labels.zoomOut, "data-ui-world-map-zoom": "out", disabled: true, size: "icon", variant: "outline", children: "\u2212" }), _jsx("output", { "aria-label": labels.level, "aria-live": "polite", "data-ui-world-map-zoom-status": true, children: "100%" }), _jsx(Button, { "aria-label": labels.zoomIn, "data-ui-world-map-zoom": "in", disabled: true, size: "icon", variant: "outline", children: "+" }), _jsx(Button, { "data-ui-world-map-zoom": "fit", disabled: true, size: "sm", variant: "outline", children: labels.fit }), _jsx(Button, { "data-ui-world-map-zoom": "reset", disabled: true, size: "sm", variant: "outline", children: labels.reset })] }));
9
+ const MapViewport = ({ children, label, zoomable }) => (_jsx("div", { "aria-label": label, className: "ui-world-map__viewport", "data-ui-world-map-viewport": true, role: "region", tabIndex: zoomable ? 0 : undefined, children: children }));
10
+ const SelectionOutline = ({ country }) => (_jsx("path", { "aria-hidden": "true", className: "ui-world-map__selection", d: country?.path ?? '' }));
11
+ const CountryPath = ({ country, highlightPatternId, interactive, isHighlighted, isSelected, label, neutralPatternId, onHoverChange, onSelect, variant }) => (_jsx("path", { className: composeClassName('ui-world-map__country', isHighlighted && 'ui-world-map__country--highlighted', isSelected && 'ui-world-map__country--selected'), d: country.path, fill: variant === 'dotted' ? `url(#${isHighlighted ? highlightPatternId : neutralPatternId})` : undefined, fillRule: "evenodd", onClick: () => {
12
+ if (interactive)
13
+ onSelect(country.id);
14
+ }, onMouseEnter: () => {
15
+ onHoverChange(country.id);
16
+ }, onMouseLeave: () => {
17
+ onHoverChange(undefined);
18
+ }, children: _jsx("title", { children: label }) }));
19
+ const MarkerPoint = ({ marker }) => {
20
+ const { x, y } = projectLumenWorldMapCoordinate(marker.longitude, marker.latitude);
21
+ return (_jsx("circle", { className: "ui-world-map__marker", cx: x, cy: y, r: 4, children: _jsx("title", { children: marker.label }) }));
22
+ };
23
+ const MarkerLayer = ({ markers }) => markers.length > 0 && (_jsx("g", { "aria-hidden": "true", className: "ui-world-map__markers", children: markers.map(marker => _jsx(MarkerPoint, { marker: marker }, marker.id)) }));
24
+ const MarkerList = ({ markers }) => markers.length > 0 && (_jsx("ul", { "aria-label": "Map markers", className: "ui-sr-only", children: markers.map(marker => _jsx("li", { children: marker.label }, marker.id)) }));
25
+ const DotPatterns = ({ highlightPatternId, neutralPatternId }) => (_jsxs("defs", { children: [_jsx("pattern", { height: 4, id: neutralPatternId, patternUnits: "userSpaceOnUse", width: 4, children: _jsx("circle", { className: composeClassName('ui-world-map__dot', 'ui-world-map__dot--neutral'), cx: 2, cy: 2, r: 1.1 }) }), _jsx("pattern", { height: 4, id: highlightPatternId, patternUnits: "userSpaceOnUse", width: 4, children: _jsx("circle", { className: composeClassName('ui-world-map__dot', 'ui-world-map__dot--highlight'), cx: 2, cy: 2, r: 1.1 }) })] }));
26
+ const Inspection = ({ country, labels }) => country && (_jsx("span", { className: "ui-world-map__inspection", children: resolveLumenWorldMapCountryLabel(country, labels) }));
27
+ const MapCaption = ({ caption }) => caption && _jsx("figcaption", { children: caption });
28
+ const SelectControl = ({ countries, labelOverrides, listLabel, onSelect, selectedId }) => (_jsxs("label", { className: "ui-world-map__select-label", children: [_jsx("span", { children: listLabel }), _jsxs("select", { className: "ui-select ui-world-map__select", onChange: event => {
29
+ onSelect(event.currentTarget.value);
30
+ }, value: selectedId ?? '', children: [_jsx("option", { value: "", children: listLabel }), countries.map(country => (_jsx("option", { value: country.id, children: resolveLumenWorldMapCountryLabel(country, labelOverrides) }, country.id)))] })] }));
31
+ const HighlightedList = ({ countries, highlightedIds, labelOverrides }) => highlightedIds.length > 0 && (_jsx("ul", { "aria-label": "Highlighted countries", className: "ui-world-map__highlights", children: highlightedIds.map(id => {
32
+ const country = findLumenWorldMapCountry(countries, id);
33
+ return country && _jsx("li", { children: resolveLumenWorldMapCountryLabel(country, labelOverrides) }, id);
34
+ }) }));
35
+ const MapHeading = ({ description, heading }) => (heading || description) && (_jsxs("header", { className: "ui-world-map__heading", children: [heading && _jsx("h3", { children: heading }), description && _jsx("p", { children: description })] }));
36
+ const isCurrentCountry = (country, id) => country?.id === id;
37
+ export const WorldMap = ({ animated = true, caption, className, countries: inputCountries, defaultSelectedCountry, description, heading, highlightedCountries, interactive = true, label, labels, listLabel = 'Choose a country', markers, onCountrySelect, onSelectedCountryChange, selectedCountry, variant = 'dotted', initialView, zoomable: zoomEnabled, zoomLabels, ...props }) => {
38
+ const zoomable = zoomEnabled !== false;
39
+ const rootRef = useRef(null);
40
+ const zoomText = { ...lumenWorldMapZoomLabels, ...zoomLabels };
41
+ useEffect(() => {
42
+ const root = rootRef.current;
43
+ const abort = new AbortController();
44
+ if (root)
45
+ initLumenWorldMapZoom(root, abort.signal);
46
+ return () => {
47
+ abort.abort();
48
+ };
49
+ }, [zoomable, initialView]);
50
+ const countries = useMemo(() => normalizeLumenWorldMapCountries(inputCountries), [inputCountries]);
51
+ const instanceId = useId().replaceAll(':', '');
52
+ const neutralPatternId = `${instanceId}-dot-neutral`;
53
+ const highlightPatternId = `${instanceId}-dot-highlight`;
54
+ const [internalSelectedId, setInternalSelectedId] = useState(defaultSelectedCountry);
55
+ const [hoveredId, setHoveredId] = useState(undefined);
56
+ const selectedId = findLumenWorldMapCountry(countries, selectedCountry ?? internalSelectedId)?.id;
57
+ const highlightedIds = useMemo(() => normalizeLumenWorldMapHighlightedCountries(highlightedCountries, countries), [highlightedCountries, countries]);
58
+ const highlightedSet = useMemo(() => new Set(highlightedIds), [highlightedIds]);
59
+ useEffect(() => {
60
+ const button = rootRef.current?.querySelector('[data-ui-world-map-zoom="fit"]');
61
+ if (!button)
62
+ return;
63
+ button.disabled = highlightedIds.length === 0;
64
+ button.classList.toggle('ui-button--disabled', button.disabled);
65
+ }, [highlightedIds, zoomable]);
66
+ const normalizedMarkers = useMemo(() => normalizeLumenWorldMapMarkers(markers), [markers]);
67
+ const activeId = hoveredId ?? selectedId;
68
+ const activeCountry = findLumenWorldMapCountry(countries, activeId);
69
+ const { height: viewBoxHeight, width: viewBoxWidth } = LUMEN_WORLD_MAP_VIEW_BOX;
70
+ const selectCountry = (countryId) => {
71
+ const country = findLumenWorldMapCountry(countries, countryId);
72
+ if (isCurrentCountry(country, selectedId))
73
+ return;
74
+ if (selectedCountry === undefined)
75
+ setInternalSelectedId(country?.id);
76
+ onSelectedCountryChange?.(country?.id ?? '');
77
+ if (country)
78
+ onCountrySelect?.(createLumenWorldMapSelectDetail(country, highlightedSet, labels));
79
+ };
80
+ return (_jsxs("figure", { ...props, ref: rootRef, className: composeClassName('ui-world-map', className), "data-initial-view": initialView, "data-animated": animated, "data-interactive": interactive, "data-variant": variant, children: [_jsx(MapHeading, { description: description, heading: heading }), _jsx(ZoomControls, { enabled: zoomable, labels: zoomText }), _jsxs("div", { className: "ui-world-map__frame", children: [_jsx(MapViewport, { label: `${zoomText.viewport}: ${label}`, zoomable: zoomable, children: _jsxs("svg", { "aria-label": label, className: "ui-world-map__plot", role: "img", viewBox: `0 0 ${viewBoxWidth} ${viewBoxHeight}`, children: [variant === 'dotted' && (_jsx(DotPatterns, { highlightPatternId: highlightPatternId, neutralPatternId: neutralPatternId })), _jsx("g", { "aria-hidden": "true", className: "ui-world-map__countries", children: countries.map(country => (_jsx(CountryPath, { country: country, highlightPatternId: highlightPatternId, interactive: interactive, isHighlighted: highlightedSet.has(country.id), isSelected: selectedId === country.id, label: resolveLumenWorldMapCountryLabel(country, labels), neutralPatternId: neutralPatternId, onHoverChange: setHoveredId, onSelect: selectCountry, variant: variant }, country.id))) }), _jsx(MarkerLayer, { markers: normalizedMarkers }), _jsx(SelectionOutline, { country: findLumenWorldMapCountry(countries, selectedId) })] }) }), _jsx(Inspection, { country: activeCountry, labels: labels })] }), interactive && (_jsx(SelectControl, { countries: countries, labelOverrides: labels, listLabel: listLabel, onSelect: selectCountry, selectedId: selectedId })), _jsx(HighlightedList, { countries: countries, highlightedIds: highlightedIds, labelOverrides: labels }), _jsx(MarkerList, { markers: normalizedMarkers }), _jsx(MapCaption, { caption: caption })] }));
81
+ };
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "@santi020k/lumen-react",
3
- "version": "3.0.0",
3
+ "version": "4.0.0",
4
4
  "publishConfig": {
5
5
  "access": "public"
6
6
  },
@@ -9,7 +9,8 @@
9
9
  "sideEffects": [
10
10
  "./layers.css",
11
11
  "./styles.css",
12
- "./styles/critical.css"
12
+ "./styles/critical.css",
13
+ "./styles/data-table-view.css"
13
14
  ],
14
15
  "main": "./dist/index.js",
15
16
  "module": "./dist/index.js",
@@ -30,6 +31,83 @@
30
31
  "./icons": {
31
32
  "types": "./dist/icons.d.ts",
32
33
  "import": "./dist/icons.js"
34
+ },
35
+ "./components/attachments": {
36
+ "types": "./dist/attachments.d.ts",
37
+ "import": "./dist/attachments.js"
38
+ },
39
+ "./components/bullet-chart": {
40
+ "types": "./dist/bullet-chart.d.ts",
41
+ "import": "./dist/bullet-chart.js"
42
+ },
43
+ "./components/comparison-chart": {
44
+ "types": "./dist/comparison-chart.d.ts",
45
+ "import": "./dist/comparison-chart.js"
46
+ },
47
+ "./components/data-table": {
48
+ "types": "./dist/data-table.d.ts",
49
+ "import": "./dist/data-table.js"
50
+ },
51
+ "./components/date-range-calendar": {
52
+ "types": "./dist/date-range-calendar.d.ts",
53
+ "import": "./dist/date-range-calendar.js"
54
+ },
55
+ "./components/date-range-input": {
56
+ "types": "./dist/date-range-input.d.ts",
57
+ "import": "./dist/date-range-input.js"
58
+ },
59
+ "./components/expanded-charts": {
60
+ "types": "./dist/expanded-charts.d.ts",
61
+ "import": "./dist/expanded-charts.js"
62
+ },
63
+ "./components/image-comparison": {
64
+ "types": "./dist/image-comparison.d.ts",
65
+ "import": "./dist/image-comparison.js"
66
+ },
67
+ "./components/interval-charts": {
68
+ "types": "./dist/interval-charts.d.ts",
69
+ "import": "./dist/interval-charts.js"
70
+ },
71
+ "./components/virtual-list": {
72
+ "types": "./dist/virtual-list.d.ts",
73
+ "import": "./dist/virtual-list.js"
74
+ },
75
+ "./components/world-map": {
76
+ "types": "./dist/world-map.d.ts",
77
+ "import": "./dist/world-map.js"
78
+ },
79
+ "./hooks": {
80
+ "types": "./dist/hooks.d.ts",
81
+ "import": "./dist/hooks.js"
82
+ },
83
+ "./components/data-table-view": {
84
+ "types": "./dist/data-table-view.d.ts",
85
+ "import": "./dist/data-table-view.js"
86
+ },
87
+ "./styles/data-table-view.css": "./styles/data-table-view.css",
88
+ "./forms": {
89
+ "types": "./dist/form-workflow.d.ts",
90
+ "import": "./dist/form-workflow.js"
91
+ },
92
+ "./components/device-frame": {
93
+ "types": "./dist/device-frame.d.ts",
94
+ "import": "./dist/device-frame.js"
95
+ },
96
+ "./motion": {
97
+ "types": "./dist/motion.d.ts",
98
+ "import": "./dist/motion.js"
99
+ },
100
+ "./components/data-table-saved-views": {
101
+ "types": "./dist/data-table-saved-views.d.ts",
102
+ "import": "./dist/data-table-saved-views.js"
103
+ },
104
+ "./components/media-viewport": {
105
+ "types": "./dist/media-viewport.d.ts",
106
+ "import": "./dist/media-viewport.js"
107
+ },
108
+ "./components/media-selection": {
109
+ "types": "./dist/media-selection.d.ts",
110
+ "import": "./dist/media-selection.js"
33
111
  }
34
112
  },
35
113
  "files": [
@@ -45,22 +123,31 @@
45
123
  "lumen": "./bin/lumen.mjs"
46
124
  },
47
125
  "dependencies": {
48
- "@santi020k/lumen": "^3.0.0",
49
- "@santi020k/lumen-core": "^3.0.0",
126
+ "@santi020k/lumen": "^4.0.0",
127
+ "@santi020k/lumen-core": "^4.0.0",
128
+ "@tanstack/react-table": "9.2.4",
50
129
  "uqr": "^0.1.3"
51
130
  },
52
131
  "devDependencies": {
53
- "@types/react": "~19.2.4",
54
- "@types/react-dom": "~19.2.5",
55
- "@vitest/coverage-v8": "^5.0.1",
132
+ "@types/react": "~19.2.18",
133
+ "@types/react-dom": "~19.2.7",
134
+ "@vitest/coverage-v8": "^5.0.3",
135
+ "esbuild": "^0.28.2",
56
136
  "jsdom": "^30.1.1",
137
+ "motion": "14.0.0",
57
138
  "react": "19.2.3",
58
139
  "react-dom": "19.2.3",
59
140
  "typescript": "~6.0.3",
60
- "vitest": "^5.0.1"
141
+ "vitest": "^5.0.3"
61
142
  },
62
143
  "peerDependencies": {
63
- "react": ">=19"
144
+ "react": ">=19",
145
+ "motion": "^14.0.0"
146
+ },
147
+ "peerDependenciesMeta": {
148
+ "motion": {
149
+ "optional": true
150
+ }
64
151
  },
65
152
  "engines": {
66
153
  "node": ">=22.12.0"
@@ -88,13 +175,14 @@
88
175
  },
89
176
  "license": "MIT",
90
177
  "scripts": {
91
- "build": "tsc -p tsconfig.build.json",
178
+ "build": "tsc -p tsconfig.build.json && node scripts/minify-build.mjs",
92
179
  "dev": "tsc -p tsconfig.build.json --watch --preserveWatchOutput",
93
180
  "typecheck": "tsc -p tsconfig.json --noEmit",
94
181
  "test": "vitest run --config ../../vitest.config.ts --project react",
95
182
  "test:coverage": "vitest run --config ../../vitest.config.ts --project react --coverage",
96
183
  "lint": "eslint . --no-warn-ignored --max-warnings=0",
97
184
  "lint:fix": "eslint . --fix --no-warn-ignored --max-warnings=0",
98
- "clean": "rm -rf dist coverage"
185
+ "clean": "rm -rf dist coverage",
186
+ "measure:selective-imports": "node scripts/measure-selective-imports.mjs"
99
187
  }
100
188
  }