@proyecto-viviana/solidaria-components 0.2.5 → 0.3.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/LICENSE +21 -0
- package/README.md +39 -272
- package/dist/ActionBar.d.ts +79 -0
- package/dist/ActionBar.d.ts.map +1 -0
- package/dist/ActionGroup.d.ts +74 -0
- package/dist/ActionGroup.d.ts.map +1 -0
- package/dist/Alert.d.ts +70 -0
- package/dist/Alert.d.ts.map +1 -0
- package/dist/Autocomplete.d.ts +5 -5
- package/dist/Autocomplete.d.ts.map +1 -1
- package/dist/Breadcrumbs.d.ts +27 -8
- package/dist/Breadcrumbs.d.ts.map +1 -1
- package/dist/Button.d.ts +28 -5
- package/dist/Button.d.ts.map +1 -1
- package/dist/Calendar.d.ts +51 -7
- package/dist/Calendar.d.ts.map +1 -1
- package/dist/Checkbox.d.ts +33 -8
- package/dist/Checkbox.d.ts.map +1 -1
- package/dist/Collection.d.ts +130 -0
- package/dist/Collection.d.ts.map +1 -0
- package/dist/Color.d.ts +210 -9
- package/dist/Color.d.ts.map +1 -1
- package/dist/ColorEditor.d.ts +42 -0
- package/dist/ColorEditor.d.ts.map +1 -0
- package/dist/ComboBox.d.ts +146 -16
- package/dist/ComboBox.d.ts.map +1 -1
- package/dist/ContextualHelpTrigger.d.ts +40 -0
- package/dist/ContextualHelpTrigger.d.ts.map +1 -0
- package/dist/DateField.d.ts +35 -8
- package/dist/DateField.d.ts.map +1 -1
- package/dist/DatePicker.d.ts +101 -5
- package/dist/DatePicker.d.ts.map +1 -1
- package/dist/DateRangePickerContext.d.ts +30 -0
- package/dist/DateRangePickerContext.d.ts.map +1 -0
- package/dist/Dialog.d.ts +5 -5
- package/dist/Dialog.d.ts.map +1 -1
- package/dist/Disclosure.d.ts +25 -5
- package/dist/Disclosure.d.ts.map +1 -1
- package/dist/DragAndDrop.d.ts +80 -0
- package/dist/DragAndDrop.d.ts.map +1 -0
- package/dist/DragPreview.d.ts +14 -0
- package/dist/DragPreview.d.ts.map +1 -0
- package/dist/DropZone.d.ts +27 -0
- package/dist/DropZone.d.ts.map +1 -0
- package/dist/FieldError.d.ts +27 -0
- package/dist/FieldError.d.ts.map +1 -0
- package/dist/FileTrigger.d.ts +26 -0
- package/dist/FileTrigger.d.ts.map +1 -0
- package/dist/Focusable.d.ts +27 -0
- package/dist/Focusable.d.ts.map +1 -0
- package/dist/Form.d.ts +41 -0
- package/dist/Form.d.ts.map +1 -0
- package/dist/GridList.d.ts +69 -10
- package/dist/GridList.d.ts.map +1 -1
- package/dist/HiddenDateInput.d.ts +26 -0
- package/dist/HiddenDateInput.d.ts.map +1 -0
- package/dist/HiddenTimeInput.d.ts +25 -0
- package/dist/HiddenTimeInput.d.ts.map +1 -0
- package/dist/Icon.d.ts +57 -0
- package/dist/Icon.d.ts.map +1 -0
- package/dist/Keyboard.d.ts +13 -0
- package/dist/Keyboard.d.ts.map +1 -0
- package/dist/Landmark.d.ts +3 -3
- package/dist/Landmark.d.ts.map +1 -1
- package/dist/Link.d.ts +10 -4
- package/dist/Link.d.ts.map +1 -1
- package/dist/ListBox.d.ts +73 -11
- package/dist/ListBox.d.ts.map +1 -1
- package/dist/ListDropTargetDelegate.d.ts +38 -0
- package/dist/ListDropTargetDelegate.d.ts.map +1 -0
- package/dist/Menu.d.ts +79 -10
- package/dist/Menu.d.ts.map +1 -1
- package/dist/Meter.d.ts +4 -4
- package/dist/Meter.d.ts.map +1 -1
- package/dist/Modal.d.ts +6 -4
- package/dist/Modal.d.ts.map +1 -1
- package/dist/NumberField.d.ts +10 -12
- package/dist/NumberField.d.ts.map +1 -1
- package/dist/Popover.d.ts +32 -7
- package/dist/Popover.d.ts.map +1 -1
- package/dist/Pressable.d.ts +27 -0
- package/dist/Pressable.d.ts.map +1 -0
- package/dist/ProgressBar.d.ts +6 -4
- package/dist/ProgressBar.d.ts.map +1 -1
- package/dist/RadioGroup.d.ts +43 -9
- package/dist/RadioGroup.d.ts.map +1 -1
- package/dist/RangeCalendar.d.ts +39 -7
- package/dist/RangeCalendar.d.ts.map +1 -1
- package/dist/RouterProvider.d.ts +75 -0
- package/dist/RouterProvider.d.ts.map +1 -0
- package/dist/SearchField.d.ts +23 -21
- package/dist/SearchField.d.ts.map +1 -1
- package/dist/Select.d.ts +48 -7
- package/dist/Select.d.ts.map +1 -1
- package/dist/SelectionIndicator.d.ts +30 -0
- package/dist/SelectionIndicator.d.ts.map +1 -0
- package/dist/Separator.d.ts +9 -3
- package/dist/Separator.d.ts.map +1 -1
- package/dist/SharedElementTransition.d.ts +41 -0
- package/dist/SharedElementTransition.d.ts.map +1 -0
- package/dist/Slider.d.ts +15 -8
- package/dist/Slider.d.ts.map +1 -1
- package/dist/StepList.d.ts +90 -0
- package/dist/StepList.d.ts.map +1 -0
- package/dist/Switch.d.ts +11 -5
- package/dist/Switch.d.ts.map +1 -1
- package/dist/Table.d.ts +222 -19
- package/dist/Table.d.ts.map +1 -1
- package/dist/Tabs.d.ts +47 -10
- package/dist/Tabs.d.ts.map +1 -1
- package/dist/TagGroup.d.ts +22 -10
- package/dist/TagGroup.d.ts.map +1 -1
- package/dist/Text.d.ts +10 -0
- package/dist/Text.d.ts.map +1 -0
- package/dist/TextField.d.ts +19 -11
- package/dist/TextField.d.ts.map +1 -1
- package/dist/TimeField.d.ts +32 -7
- package/dist/TimeField.d.ts.map +1 -1
- package/dist/Toast.d.ts +29 -14
- package/dist/Toast.d.ts.map +1 -1
- package/dist/ToggleButton.d.ts +36 -0
- package/dist/ToggleButton.d.ts.map +1 -0
- package/dist/ToggleButtonGroup.d.ts +33 -0
- package/dist/ToggleButtonGroup.d.ts.map +1 -0
- package/dist/Toolbar.d.ts +7 -3
- package/dist/Toolbar.d.ts.map +1 -1
- package/dist/Tooltip.d.ts +58 -7
- package/dist/Tooltip.d.ts.map +1 -1
- package/dist/Tree.d.ts +102 -11
- package/dist/Tree.d.ts.map +1 -1
- package/dist/Virtualizer.d.ts +61 -0
- package/dist/Virtualizer.d.ts.map +1 -0
- package/dist/VirtualizerLayouts.d.ts +82 -0
- package/dist/VirtualizerLayouts.d.ts.map +1 -0
- package/dist/VisuallyHidden.d.ts +4 -2
- package/dist/VisuallyHidden.d.ts.map +1 -1
- package/dist/contexts.d.ts +6 -1
- package/dist/contexts.d.ts.map +1 -1
- package/dist/index.d.ts +73 -39
- package/dist/index.d.ts.map +1 -1
- package/dist/index.js +23342 -10644
- package/dist/index.js.map +1 -7
- package/dist/index.jsx +18110 -0
- package/dist/index.jsx.map +1 -0
- package/dist/useDragAndDrop.d.ts +93 -0
- package/dist/useDragAndDrop.d.ts.map +1 -0
- package/dist/utils.d.ts +8 -2
- package/dist/utils.d.ts.map +1 -1
- package/dist/virtualizer/Layout.d.ts +79 -0
- package/dist/virtualizer/Layout.d.ts.map +1 -0
- package/package.json +33 -32
- package/src/ActionBar.tsx +251 -0
- package/src/ActionGroup.tsx +277 -0
- package/src/Alert.tsx +152 -0
- package/src/Autocomplete.tsx +39 -44
- package/src/Breadcrumbs.tsx +227 -72
- package/src/Button.tsx +315 -74
- package/src/Calendar.tsx +347 -141
- package/src/Checkbox.tsx +414 -123
- package/src/Collection.tsx +350 -0
- package/src/Color.tsx +1325 -284
- package/src/ColorEditor.tsx +213 -0
- package/src/ComboBox.tsx +644 -245
- package/src/ContextualHelpTrigger.tsx +195 -0
- package/src/DateField.tsx +274 -106
- package/src/DatePicker.tsx +892 -111
- package/src/DateRangePickerContext.tsx +44 -0
- package/src/Dialog.tsx +173 -104
- package/src/Disclosure.tsx +158 -105
- package/src/DragAndDrop.tsx +340 -0
- package/src/DragPreview.tsx +47 -0
- package/src/DropZone.tsx +233 -0
- package/src/FieldError.tsx +89 -0
- package/src/FileTrigger.tsx +83 -0
- package/src/Focusable.tsx +103 -0
- package/src/Form.tsx +140 -0
- package/src/GridList.tsx +542 -128
- package/src/HiddenDateInput.tsx +153 -0
- package/src/HiddenTimeInput.tsx +133 -0
- package/src/Icon.tsx +133 -0
- package/src/Keyboard.tsx +26 -0
- package/src/Landmark.tsx +37 -63
- package/src/Link.tsx +132 -69
- package/src/ListBox.tsx +656 -106
- package/src/ListDropTargetDelegate.ts +283 -0
- package/src/Menu.tsx +1234 -132
- package/src/Meter.tsx +44 -58
- package/src/Modal.tsx +262 -166
- package/src/NumberField.tsx +267 -151
- package/src/Popover.tsx +452 -343
- package/src/Pressable.tsx +108 -0
- package/src/ProgressBar.tsx +54 -59
- package/src/RadioGroup.tsx +533 -121
- package/src/RangeCalendar.tsx +249 -150
- package/src/RouterProvider.tsx +223 -0
- package/src/SearchField.tsx +460 -133
- package/src/Select.tsx +804 -233
- package/src/SelectionIndicator.tsx +108 -0
- package/src/Separator.tsx +47 -49
- package/src/SharedElementTransition.tsx +264 -0
- package/src/Slider.tsx +148 -98
- package/src/StepList.tsx +272 -0
- package/src/Switch.tsx +93 -46
- package/src/Table.tsx +1551 -225
- package/src/Tabs.tsx +377 -123
- package/src/TagGroup.tsx +233 -135
- package/src/Text.tsx +18 -0
- package/src/TextField.tsx +413 -86
- package/src/TimeField.tsx +232 -222
- package/src/Toast.tsx +306 -160
- package/src/ToggleButton.tsx +169 -0
- package/src/ToggleButtonGroup.tsx +141 -0
- package/src/Toolbar.tsx +61 -70
- package/src/Tooltip.tsx +473 -116
- package/src/Tree.tsx +1514 -175
- package/src/Virtualizer.tsx +730 -0
- package/src/VirtualizerLayouts.ts +280 -0
- package/src/VisuallyHidden.tsx +32 -38
- package/src/contexts.ts +29 -36
- package/src/index.ts +972 -620
- package/src/useDragAndDrop.ts +367 -0
- package/src/utils.tsx +69 -50
- package/src/virtualizer/Layout.ts +192 -0
- package/dist/index.ssr.js +0 -9785
- package/dist/index.ssr.js.map +0 -7
|
@@ -0,0 +1,340 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* Drag and drop composition helpers for solidaria-components.
|
|
3
|
+
*
|
|
4
|
+
* Compatibility target: react-aria-components DragAndDrop exports.
|
|
5
|
+
*/
|
|
6
|
+
|
|
7
|
+
import { type JSX, type Accessor, createContext, createMemo, useContext } from "solid-js";
|
|
8
|
+
import type {
|
|
9
|
+
DragTypes,
|
|
10
|
+
DropOperation,
|
|
11
|
+
DropTarget,
|
|
12
|
+
ItemDropTarget,
|
|
13
|
+
Key,
|
|
14
|
+
} from "@proyecto-viviana/solid-stately";
|
|
15
|
+
import type { DragAndDropHooks } from "./useDragAndDrop";
|
|
16
|
+
import {
|
|
17
|
+
type ClassNameOrFunction,
|
|
18
|
+
type StyleOrFunction,
|
|
19
|
+
type SlotProps,
|
|
20
|
+
useRenderProps,
|
|
21
|
+
dataAttr,
|
|
22
|
+
} from "./utils";
|
|
23
|
+
|
|
24
|
+
export interface DragAndDropContextValue {
|
|
25
|
+
dragAndDropHooks?: DragAndDropHooks<unknown>;
|
|
26
|
+
dragState?: unknown;
|
|
27
|
+
dropState?: {
|
|
28
|
+
target?: DropTarget | null;
|
|
29
|
+
isDropTarget?: (target: DropTarget) => boolean;
|
|
30
|
+
};
|
|
31
|
+
}
|
|
32
|
+
|
|
33
|
+
export const DragAndDropContext = createContext<DragAndDropContextValue>({});
|
|
34
|
+
|
|
35
|
+
export interface DropIndicatorRenderProps {
|
|
36
|
+
isDropTarget: boolean;
|
|
37
|
+
}
|
|
38
|
+
|
|
39
|
+
export interface DropIndicatorProps extends SlotProps {
|
|
40
|
+
target: ItemDropTarget;
|
|
41
|
+
children?: JSX.Element | ((props: DropIndicatorRenderProps) => JSX.Element);
|
|
42
|
+
class?: ClassNameOrFunction<DropIndicatorRenderProps>;
|
|
43
|
+
style?: StyleOrFunction<DropIndicatorRenderProps>;
|
|
44
|
+
}
|
|
45
|
+
|
|
46
|
+
interface DropIndicatorContextValue {
|
|
47
|
+
render: (props: DropIndicatorProps) => JSX.Element;
|
|
48
|
+
}
|
|
49
|
+
|
|
50
|
+
export const DropIndicatorContext = createContext<DropIndicatorContextValue | null>(null);
|
|
51
|
+
|
|
52
|
+
function DefaultDropIndicator(props: DropIndicatorProps): JSX.Element {
|
|
53
|
+
const dnd = useContext(DragAndDropContext);
|
|
54
|
+
const isDropTarget = createMemo(() => {
|
|
55
|
+
const target = props.target;
|
|
56
|
+
return dnd.dropState?.isDropTarget?.(target) ?? false;
|
|
57
|
+
});
|
|
58
|
+
|
|
59
|
+
const renderProps = useRenderProps(
|
|
60
|
+
{
|
|
61
|
+
children: props.children,
|
|
62
|
+
class: props.class,
|
|
63
|
+
style: props.style,
|
|
64
|
+
defaultClassName: "solidaria-DropIndicator",
|
|
65
|
+
},
|
|
66
|
+
() => ({
|
|
67
|
+
isDropTarget: isDropTarget(),
|
|
68
|
+
}),
|
|
69
|
+
);
|
|
70
|
+
|
|
71
|
+
return (
|
|
72
|
+
<div
|
|
73
|
+
role="option"
|
|
74
|
+
aria-disabled={true}
|
|
75
|
+
class={renderProps.class()}
|
|
76
|
+
style={renderProps.style()}
|
|
77
|
+
data-drop-target={dataAttr(isDropTarget())}
|
|
78
|
+
>
|
|
79
|
+
{renderProps.renderChildren()}
|
|
80
|
+
</div>
|
|
81
|
+
);
|
|
82
|
+
}
|
|
83
|
+
|
|
84
|
+
export function DropIndicator(props: DropIndicatorProps): JSX.Element {
|
|
85
|
+
const context = useContext(DropIndicatorContext);
|
|
86
|
+
if (context) return context.render(props);
|
|
87
|
+
return <DefaultDropIndicator {...props} />;
|
|
88
|
+
}
|
|
89
|
+
|
|
90
|
+
export function useRenderDropIndicator(
|
|
91
|
+
hooksOrDropState?:
|
|
92
|
+
| Pick<
|
|
93
|
+
DragAndDropHooks<unknown>,
|
|
94
|
+
"renderDropIndicator" | "isVirtualDragging" | "useDropIndicator"
|
|
95
|
+
>
|
|
96
|
+
| {
|
|
97
|
+
target?: DropTarget | null;
|
|
98
|
+
isDropTarget?: ((target: DropTarget) => boolean) | boolean;
|
|
99
|
+
},
|
|
100
|
+
maybeDropState?: {
|
|
101
|
+
target?: DropTarget | null;
|
|
102
|
+
isDropTarget?: ((target: DropTarget) => boolean) | boolean;
|
|
103
|
+
},
|
|
104
|
+
): ((target: ItemDropTarget) => JSX.Element | undefined) | undefined {
|
|
105
|
+
const looksLikeDropState = (
|
|
106
|
+
value: unknown,
|
|
107
|
+
): value is {
|
|
108
|
+
target?: DropTarget | null;
|
|
109
|
+
isDropTarget?: ((target: DropTarget) => boolean) | boolean;
|
|
110
|
+
} => {
|
|
111
|
+
return Boolean(
|
|
112
|
+
value &&
|
|
113
|
+
typeof value === "object" &&
|
|
114
|
+
("isDropTarget" in (value as Record<string, unknown>) ||
|
|
115
|
+
"target" in (value as Record<string, unknown>)),
|
|
116
|
+
);
|
|
117
|
+
};
|
|
118
|
+
|
|
119
|
+
const dragAndDropHooks = looksLikeDropState(hooksOrDropState) ? undefined : hooksOrDropState;
|
|
120
|
+
const dropState = looksLikeDropState(hooksOrDropState) ? hooksOrDropState : maybeDropState;
|
|
121
|
+
|
|
122
|
+
// RAC only renders collection indicators when drop hooks are present.
|
|
123
|
+
if (dragAndDropHooks && !dragAndDropHooks.useDropIndicator) return undefined;
|
|
124
|
+
if (!dropState && !dragAndDropHooks?.renderDropIndicator) return undefined;
|
|
125
|
+
|
|
126
|
+
const targetsEqual = (a: DropTarget | null | undefined, b: DropTarget): boolean => {
|
|
127
|
+
if (!a) return false;
|
|
128
|
+
if (a.type !== b.type) return false;
|
|
129
|
+
if (a.type === "root" && b.type === "root") return true;
|
|
130
|
+
if (a.type !== "item" || b.type !== "item") return false;
|
|
131
|
+
return a.key === b.key && a.dropPosition === b.dropPosition;
|
|
132
|
+
};
|
|
133
|
+
|
|
134
|
+
return (target: ItemDropTarget) => {
|
|
135
|
+
const stateIsDropTarget = dropState?.isDropTarget;
|
|
136
|
+
const isTarget =
|
|
137
|
+
typeof stateIsDropTarget === "function"
|
|
138
|
+
? stateIsDropTarget(target)
|
|
139
|
+
: stateIsDropTarget === true
|
|
140
|
+
? targetsEqual(dropState?.target, target)
|
|
141
|
+
: false;
|
|
142
|
+
const isVirtualDragging = dragAndDropHooks?.isVirtualDragging?.() ?? false;
|
|
143
|
+
if (!isTarget && !isVirtualDragging) return undefined;
|
|
144
|
+
return dragAndDropHooks?.renderDropIndicator ? (
|
|
145
|
+
dragAndDropHooks.renderDropIndicator(target)
|
|
146
|
+
) : (
|
|
147
|
+
<DropIndicator target={target} />
|
|
148
|
+
);
|
|
149
|
+
};
|
|
150
|
+
}
|
|
151
|
+
|
|
152
|
+
type KeyAccessor = Key | null | undefined | Accessor<Key | null | undefined>;
|
|
153
|
+
|
|
154
|
+
interface SelectionManagerLike {
|
|
155
|
+
focusedKey?: KeyAccessor;
|
|
156
|
+
}
|
|
157
|
+
|
|
158
|
+
interface CollectionLike {
|
|
159
|
+
getKeyAfter: (key: Key) => Key | null;
|
|
160
|
+
getItem: (key: Key) => { level?: number; type?: string } | null | undefined;
|
|
161
|
+
}
|
|
162
|
+
|
|
163
|
+
interface DroppableCollectionStateLike {
|
|
164
|
+
target?: DropTarget | null;
|
|
165
|
+
}
|
|
166
|
+
|
|
167
|
+
export interface VirtualRangeLike {
|
|
168
|
+
start: number;
|
|
169
|
+
end: number;
|
|
170
|
+
offsetTop: number;
|
|
171
|
+
offsetBottom: number;
|
|
172
|
+
}
|
|
173
|
+
|
|
174
|
+
export interface LayoutInfoProviderLike {
|
|
175
|
+
getLayoutInfo: (index: number) => { rect: { y: number; height: number } };
|
|
176
|
+
}
|
|
177
|
+
|
|
178
|
+
function resolveKey(value: KeyAccessor): Key | null | undefined {
|
|
179
|
+
if (typeof value === "function") {
|
|
180
|
+
return (value as Accessor<Key | null | undefined>)();
|
|
181
|
+
}
|
|
182
|
+
return value;
|
|
183
|
+
}
|
|
184
|
+
|
|
185
|
+
function getAfterDropNormalizedKey(target: ItemDropTarget, collection?: CollectionLike): Key {
|
|
186
|
+
if (target.dropPosition !== "after" || !collection) return target.key;
|
|
187
|
+
|
|
188
|
+
let nextKey = collection.getKeyAfter(target.key);
|
|
189
|
+
let lastDescendantKey: Key | null = null;
|
|
190
|
+
|
|
191
|
+
if (nextKey != null) {
|
|
192
|
+
const targetLevel = collection.getItem(target.key)?.level ?? 0;
|
|
193
|
+
while (nextKey != null) {
|
|
194
|
+
const node = collection.getItem(nextKey);
|
|
195
|
+
if (!node) break;
|
|
196
|
+
if (node.type && node.type !== "item") {
|
|
197
|
+
nextKey = collection.getKeyAfter(nextKey);
|
|
198
|
+
continue;
|
|
199
|
+
}
|
|
200
|
+
if ((node.level ?? 0) <= targetLevel) break;
|
|
201
|
+
lastDescendantKey = nextKey;
|
|
202
|
+
nextKey = collection.getKeyAfter(nextKey);
|
|
203
|
+
}
|
|
204
|
+
}
|
|
205
|
+
|
|
206
|
+
return nextKey ?? lastDescendantKey ?? target.key;
|
|
207
|
+
}
|
|
208
|
+
|
|
209
|
+
export function getNormalizedDropTargetKey(
|
|
210
|
+
target: DropTarget | null | undefined,
|
|
211
|
+
collection?: CollectionLike,
|
|
212
|
+
): Key | null {
|
|
213
|
+
if (!target || target.type !== "item") return null;
|
|
214
|
+
return getAfterDropNormalizedKey(target, collection);
|
|
215
|
+
}
|
|
216
|
+
|
|
217
|
+
export function useDndPersistedKeys(
|
|
218
|
+
selectionManager: SelectionManagerLike | null | undefined,
|
|
219
|
+
dragAndDropHooks?: Pick<DragAndDropHooks<unknown>, "isVirtualDragging">,
|
|
220
|
+
dropState?: DroppableCollectionStateLike,
|
|
221
|
+
collection?: CollectionLike,
|
|
222
|
+
): Accessor<Set<Key>> {
|
|
223
|
+
return createMemo(() => {
|
|
224
|
+
const focusedKey = resolveKey(selectionManager?.focusedKey);
|
|
225
|
+
let dropTargetKey: Key | null | undefined;
|
|
226
|
+
|
|
227
|
+
if (dragAndDropHooks?.isVirtualDragging?.() && dropState?.target?.type === "item") {
|
|
228
|
+
dropTargetKey = getNormalizedDropTargetKey(dropState.target, collection) ?? undefined;
|
|
229
|
+
}
|
|
230
|
+
|
|
231
|
+
const keys = new Set<Key>();
|
|
232
|
+
if (focusedKey != null) keys.add(focusedKey);
|
|
233
|
+
if (dropTargetKey != null) keys.add(dropTargetKey);
|
|
234
|
+
return keys;
|
|
235
|
+
});
|
|
236
|
+
}
|
|
237
|
+
|
|
238
|
+
export function mergePersistedKeysIntoVirtualRange(
|
|
239
|
+
baseRange: VirtualRangeLike,
|
|
240
|
+
persistedIndexes: number[],
|
|
241
|
+
itemCount: number,
|
|
242
|
+
layoutInfoProvider: LayoutInfoProviderLike,
|
|
243
|
+
maxExtraItems = 60,
|
|
244
|
+
options?: {
|
|
245
|
+
forceIncludeIndexes?: number[];
|
|
246
|
+
forceIncludeMaxSpan?: number;
|
|
247
|
+
fallbackToForcedWindow?: boolean;
|
|
248
|
+
},
|
|
249
|
+
): VirtualRangeLike {
|
|
250
|
+
const validPersistedIndexes = Array.from(
|
|
251
|
+
new Set(persistedIndexes.filter((index) => index >= 0 && index < itemCount)),
|
|
252
|
+
).sort((a, b) => a - b);
|
|
253
|
+
const forceIndexes = Array.from(
|
|
254
|
+
new Set(
|
|
255
|
+
(options?.forceIncludeIndexes ?? []).filter((index) => index >= 0 && index < itemCount),
|
|
256
|
+
),
|
|
257
|
+
);
|
|
258
|
+
|
|
259
|
+
if (itemCount <= 0) return baseRange;
|
|
260
|
+
if (validPersistedIndexes.length === 0 && forceIndexes.length === 0) return baseRange;
|
|
261
|
+
|
|
262
|
+
const baseSpan = Math.max(1, baseRange.end - baseRange.start);
|
|
263
|
+
const maxSpan = Math.max(baseSpan, baseSpan + maxExtraItems);
|
|
264
|
+
|
|
265
|
+
let start = baseRange.start;
|
|
266
|
+
let end = baseRange.end;
|
|
267
|
+
|
|
268
|
+
const distanceToBaseRange = (index: number): number => {
|
|
269
|
+
if (index < baseRange.start) return baseRange.start - index;
|
|
270
|
+
if (index >= baseRange.end) return index - (baseRange.end - 1);
|
|
271
|
+
return 0;
|
|
272
|
+
};
|
|
273
|
+
|
|
274
|
+
for (const index of validPersistedIndexes.sort(
|
|
275
|
+
(a, b) => distanceToBaseRange(a) - distanceToBaseRange(b),
|
|
276
|
+
)) {
|
|
277
|
+
const nextStart = Math.min(start, index);
|
|
278
|
+
const nextEnd = Math.max(end, index + 1);
|
|
279
|
+
if (nextEnd - nextStart <= maxSpan) {
|
|
280
|
+
start = nextStart;
|
|
281
|
+
end = nextEnd;
|
|
282
|
+
}
|
|
283
|
+
}
|
|
284
|
+
|
|
285
|
+
if (forceIndexes.length > 0) {
|
|
286
|
+
const forceMaxSpan = Math.max(maxSpan, options?.forceIncludeMaxSpan ?? Math.max(maxSpan, 300));
|
|
287
|
+
for (const index of forceIndexes) {
|
|
288
|
+
const nextStart = Math.min(start, index);
|
|
289
|
+
const nextEnd = Math.max(end, index + 1);
|
|
290
|
+
if (nextEnd - nextStart <= forceMaxSpan) {
|
|
291
|
+
start = nextStart;
|
|
292
|
+
end = nextEnd;
|
|
293
|
+
}
|
|
294
|
+
}
|
|
295
|
+
|
|
296
|
+
if (options?.fallbackToForcedWindow !== false) {
|
|
297
|
+
const missingForced = forceIndexes.filter((index) => index < start || index >= end);
|
|
298
|
+
if (missingForced.length > 0) {
|
|
299
|
+
const nearestForced = missingForced[0];
|
|
300
|
+
const forceMaxSpan = Math.max(
|
|
301
|
+
maxSpan,
|
|
302
|
+
options?.forceIncludeMaxSpan ?? Math.max(maxSpan, 300),
|
|
303
|
+
);
|
|
304
|
+
const windowSpan = Math.min(itemCount, Math.max(baseSpan, forceMaxSpan));
|
|
305
|
+
const centeredStart = Math.max(
|
|
306
|
+
0,
|
|
307
|
+
Math.min(itemCount - windowSpan, nearestForced - Math.floor(windowSpan / 2)),
|
|
308
|
+
);
|
|
309
|
+
start = centeredStart;
|
|
310
|
+
end = Math.min(itemCount, centeredStart + windowSpan);
|
|
311
|
+
}
|
|
312
|
+
}
|
|
313
|
+
}
|
|
314
|
+
|
|
315
|
+
if (start === baseRange.start && end === baseRange.end) return baseRange;
|
|
316
|
+
|
|
317
|
+
const startRect = start > 0 ? layoutInfoProvider.getLayoutInfo(start).rect : { y: 0, height: 0 };
|
|
318
|
+
const lastRect = layoutInfoProvider.getLayoutInfo(itemCount - 1).rect;
|
|
319
|
+
const endRect = end > 0 ? layoutInfoProvider.getLayoutInfo(end - 1).rect : { y: 0, height: 0 };
|
|
320
|
+
|
|
321
|
+
return {
|
|
322
|
+
start,
|
|
323
|
+
end,
|
|
324
|
+
offsetTop: Math.max(0, startRect.y),
|
|
325
|
+
offsetBottom: Math.max(0, lastRect.y + lastRect.height - (endRect.y + endRect.height)),
|
|
326
|
+
};
|
|
327
|
+
}
|
|
328
|
+
|
|
329
|
+
export type DropTargetDelegate = {
|
|
330
|
+
getDropTargetFromPoint: (
|
|
331
|
+
x: number,
|
|
332
|
+
y: number,
|
|
333
|
+
isValidDropTarget: (target: DropTarget) => boolean,
|
|
334
|
+
) => DropTarget | null;
|
|
335
|
+
getDropOperation: (
|
|
336
|
+
target: DropTarget,
|
|
337
|
+
types: DragTypes,
|
|
338
|
+
allowedOperations: DropOperation[],
|
|
339
|
+
) => DropOperation;
|
|
340
|
+
};
|
|
@@ -0,0 +1,47 @@
|
|
|
1
|
+
import { onCleanup, type JSX } from "solid-js";
|
|
2
|
+
import type { DragItem, DragPreviewRenderer } from "@proyecto-viviana/solid-stately";
|
|
3
|
+
|
|
4
|
+
export interface DragPreviewProps {
|
|
5
|
+
ref?: { current: DragPreviewRenderer | null };
|
|
6
|
+
children: (
|
|
7
|
+
items: DragItem[],
|
|
8
|
+
) => JSX.Element | { element: JSX.Element; x?: number; y?: number } | null | undefined;
|
|
9
|
+
}
|
|
10
|
+
|
|
11
|
+
export function DragPreview(props: DragPreviewProps): JSX.Element {
|
|
12
|
+
const hasDom = typeof HTMLElement !== "undefined";
|
|
13
|
+
const isElementNode = (value: unknown): value is HTMLElement => {
|
|
14
|
+
if (!value) return false;
|
|
15
|
+
if (hasDom && value instanceof HTMLElement) return true;
|
|
16
|
+
return typeof value === "object" && (value as { nodeType?: number }).nodeType === 1;
|
|
17
|
+
};
|
|
18
|
+
|
|
19
|
+
if (props.ref) {
|
|
20
|
+
const renderer: DragPreviewRenderer = (items, callback) => {
|
|
21
|
+
const rendered = props.children(items);
|
|
22
|
+
if (!rendered) {
|
|
23
|
+
callback(null);
|
|
24
|
+
return;
|
|
25
|
+
}
|
|
26
|
+
if (typeof rendered === "object" && rendered !== null && "element" in rendered) {
|
|
27
|
+
const previewValue = rendered as { element: unknown; x?: number; y?: number };
|
|
28
|
+
callback(
|
|
29
|
+
isElementNode(previewValue.element) ? previewValue.element : null,
|
|
30
|
+
previewValue.x,
|
|
31
|
+
previewValue.y,
|
|
32
|
+
);
|
|
33
|
+
return;
|
|
34
|
+
}
|
|
35
|
+
callback(isElementNode(rendered) ? rendered : null);
|
|
36
|
+
};
|
|
37
|
+
|
|
38
|
+
props.ref.current = renderer;
|
|
39
|
+
onCleanup(() => {
|
|
40
|
+
if (props.ref?.current === renderer) {
|
|
41
|
+
props.ref.current = null;
|
|
42
|
+
}
|
|
43
|
+
});
|
|
44
|
+
}
|
|
45
|
+
|
|
46
|
+
return null as unknown as JSX.Element;
|
|
47
|
+
}
|
package/src/DropZone.tsx
ADDED
|
@@ -0,0 +1,233 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* DropZone primitive for solidaria-components.
|
|
3
|
+
*
|
|
4
|
+
* A drop target area for drag and drop operations.
|
|
5
|
+
* Parity target: react-aria-components/src/DropZone.tsx
|
|
6
|
+
*/
|
|
7
|
+
|
|
8
|
+
import {
|
|
9
|
+
type JSX,
|
|
10
|
+
createContext,
|
|
11
|
+
createMemo,
|
|
12
|
+
createSignal,
|
|
13
|
+
mergeProps,
|
|
14
|
+
splitProps,
|
|
15
|
+
useContext,
|
|
16
|
+
} from "solid-js";
|
|
17
|
+
import {
|
|
18
|
+
createDrop,
|
|
19
|
+
createFocusRing,
|
|
20
|
+
createHover,
|
|
21
|
+
readFromDataTransfer,
|
|
22
|
+
type HoverEvents,
|
|
23
|
+
type AriaDropOptions,
|
|
24
|
+
} from "@proyecto-viviana/solidaria";
|
|
25
|
+
import {
|
|
26
|
+
type ClassNameOrFunction,
|
|
27
|
+
type StyleOrFunction,
|
|
28
|
+
type RenderChildren,
|
|
29
|
+
type SlotProps,
|
|
30
|
+
useRenderProps,
|
|
31
|
+
filterDOMProps,
|
|
32
|
+
} from "./utils";
|
|
33
|
+
import { VisuallyHidden } from "./VisuallyHidden";
|
|
34
|
+
|
|
35
|
+
export interface DropZoneRenderProps {
|
|
36
|
+
isHovered: boolean;
|
|
37
|
+
isFocused: boolean;
|
|
38
|
+
isFocusVisible: boolean;
|
|
39
|
+
isDropTarget: boolean;
|
|
40
|
+
isDisabled: boolean;
|
|
41
|
+
}
|
|
42
|
+
|
|
43
|
+
export interface DropZoneProps
|
|
44
|
+
extends
|
|
45
|
+
Omit<JSX.HTMLAttributes<HTMLDivElement>, "children" | "class" | "style" | "onDrop">,
|
|
46
|
+
Omit<AriaDropOptions, "hasDropButton">,
|
|
47
|
+
HoverEvents,
|
|
48
|
+
SlotProps {
|
|
49
|
+
children?: RenderChildren<DropZoneRenderProps>;
|
|
50
|
+
class?: ClassNameOrFunction<DropZoneRenderProps>;
|
|
51
|
+
style?: StyleOrFunction<DropZoneRenderProps>;
|
|
52
|
+
}
|
|
53
|
+
|
|
54
|
+
export const DropZoneContext = createContext<DropZoneProps | null>(null);
|
|
55
|
+
const DEFAULT_DROPZONE_LABEL = "Drop files";
|
|
56
|
+
const FOCUSABLE_SELECTOR = [
|
|
57
|
+
"a[href]",
|
|
58
|
+
"button:not([disabled])",
|
|
59
|
+
'input:not([disabled]):not([type="hidden"])',
|
|
60
|
+
"select:not([disabled])",
|
|
61
|
+
"textarea:not([disabled])",
|
|
62
|
+
'[tabindex]:not([tabindex="-1"])',
|
|
63
|
+
'[contenteditable="true"]',
|
|
64
|
+
].join(",");
|
|
65
|
+
|
|
66
|
+
function isFocusableElement(target: Element): boolean {
|
|
67
|
+
return target instanceof HTMLElement && target.matches(FOCUSABLE_SELECTOR);
|
|
68
|
+
}
|
|
69
|
+
|
|
70
|
+
/**
|
|
71
|
+
* A drop zone is an area into which one or multiple objects can be dropped.
|
|
72
|
+
*/
|
|
73
|
+
export function DropZone(props: DropZoneProps): JSX.Element {
|
|
74
|
+
const contextProps = useContext(DropZoneContext);
|
|
75
|
+
const mergedProps = mergeProps(contextProps ?? {}, props);
|
|
76
|
+
const [local, dropProps, hoverEventProps, domProps] = splitProps(
|
|
77
|
+
mergedProps,
|
|
78
|
+
["children", "class", "style", "slot", "aria-label", "aria-labelledby"],
|
|
79
|
+
[
|
|
80
|
+
"getDropOperation",
|
|
81
|
+
"getDropOperationForPoint",
|
|
82
|
+
"onDropEnter",
|
|
83
|
+
"onDropMove",
|
|
84
|
+
"onDropActivate",
|
|
85
|
+
"onDropExit",
|
|
86
|
+
"onDrop",
|
|
87
|
+
"isDisabled",
|
|
88
|
+
],
|
|
89
|
+
["onHoverStart", "onHoverEnd", "onHoverChange"],
|
|
90
|
+
);
|
|
91
|
+
|
|
92
|
+
const [dropZoneRef, setDropZoneRef] = createSignal<HTMLDivElement | null>(null);
|
|
93
|
+
const [dropButtonRef, setDropButtonRef] = createSignal<HTMLButtonElement | null>(null);
|
|
94
|
+
|
|
95
|
+
const dropAria = createDrop(() => ({
|
|
96
|
+
getDropOperation: dropProps.getDropOperation,
|
|
97
|
+
getDropOperationForPoint: dropProps.getDropOperationForPoint,
|
|
98
|
+
onDropEnter: dropProps.onDropEnter,
|
|
99
|
+
onDropMove: dropProps.onDropMove,
|
|
100
|
+
onDropActivate: dropProps.onDropActivate,
|
|
101
|
+
onDropExit: dropProps.onDropExit,
|
|
102
|
+
onDrop: dropProps.onDrop,
|
|
103
|
+
hasDropButton: true,
|
|
104
|
+
isDisabled: dropProps.isDisabled,
|
|
105
|
+
}));
|
|
106
|
+
|
|
107
|
+
const { isHovered, hoverProps } = createHover(() => ({
|
|
108
|
+
isDisabled: dropProps.isDisabled,
|
|
109
|
+
onHoverStart: hoverEventProps.onHoverStart,
|
|
110
|
+
onHoverEnd: hoverEventProps.onHoverEnd,
|
|
111
|
+
onHoverChange: hoverEventProps.onHoverChange,
|
|
112
|
+
}));
|
|
113
|
+
const { isFocused, isFocusVisible, focusProps } = createFocusRing();
|
|
114
|
+
|
|
115
|
+
const renderValues = createMemo<DropZoneRenderProps>(() => ({
|
|
116
|
+
isHovered: isHovered(),
|
|
117
|
+
isFocused: isFocused(),
|
|
118
|
+
isFocusVisible: isFocusVisible(),
|
|
119
|
+
isDropTarget: dropAria.isDropTarget,
|
|
120
|
+
isDisabled: !!dropProps.isDisabled,
|
|
121
|
+
}));
|
|
122
|
+
|
|
123
|
+
const renderProps = useRenderProps(
|
|
124
|
+
{
|
|
125
|
+
children: local.children,
|
|
126
|
+
class: local.class,
|
|
127
|
+
style: local.style,
|
|
128
|
+
defaultClassName: "solidaria-DropZone",
|
|
129
|
+
},
|
|
130
|
+
renderValues,
|
|
131
|
+
);
|
|
132
|
+
|
|
133
|
+
const filteredDomProps = createMemo(() => filterDOMProps(domProps, { global: true }));
|
|
134
|
+
|
|
135
|
+
const cleanDropProps = () => {
|
|
136
|
+
const { ref: _ref, ...rest } = dropAria.dropProps as Record<string, unknown>;
|
|
137
|
+
return rest;
|
|
138
|
+
};
|
|
139
|
+
const cleanHoverProps = () => {
|
|
140
|
+
const { ref: _ref, ...rest } = hoverProps as Record<string, unknown>;
|
|
141
|
+
return rest;
|
|
142
|
+
};
|
|
143
|
+
const cleanFocusProps = () => {
|
|
144
|
+
const { ref: _ref, ...rest } = focusProps as Record<string, unknown>;
|
|
145
|
+
return rest;
|
|
146
|
+
};
|
|
147
|
+
const cleanDropButtonProps = () => {
|
|
148
|
+
const { ref: _ref, ...rest } = dropAria.dropButtonProps as Record<string, unknown>;
|
|
149
|
+
return rest;
|
|
150
|
+
};
|
|
151
|
+
|
|
152
|
+
const onRootClick: JSX.EventHandler<HTMLDivElement, MouseEvent> = (e) => {
|
|
153
|
+
const onClick = (filteredDomProps() as JSX.HTMLAttributes<HTMLDivElement>).onClick as
|
|
154
|
+
| JSX.EventHandler<HTMLDivElement, MouseEvent>
|
|
155
|
+
| undefined;
|
|
156
|
+
onClick?.(e);
|
|
157
|
+
if (e.defaultPrevented || dropProps.isDisabled) {
|
|
158
|
+
return;
|
|
159
|
+
}
|
|
160
|
+
|
|
161
|
+
const root = dropZoneRef();
|
|
162
|
+
const hiddenButton = dropButtonRef();
|
|
163
|
+
if (!root || !hiddenButton) {
|
|
164
|
+
return;
|
|
165
|
+
}
|
|
166
|
+
|
|
167
|
+
let target: Element | null = e.target instanceof Element ? e.target : root;
|
|
168
|
+
while (target && root.contains(target)) {
|
|
169
|
+
if (isFocusableElement(target)) {
|
|
170
|
+
return;
|
|
171
|
+
}
|
|
172
|
+
if (target === root) {
|
|
173
|
+
hiddenButton.focus();
|
|
174
|
+
return;
|
|
175
|
+
}
|
|
176
|
+
target = target.parentElement;
|
|
177
|
+
}
|
|
178
|
+
};
|
|
179
|
+
|
|
180
|
+
const onHiddenButtonPaste: JSX.EventHandler<HTMLButtonElement, ClipboardEvent> = (e) => {
|
|
181
|
+
if (dropProps.isDisabled || !e.clipboardData) {
|
|
182
|
+
return;
|
|
183
|
+
}
|
|
184
|
+
|
|
185
|
+
const items = readFromDataTransfer(e.clipboardData);
|
|
186
|
+
if (items.length === 0) {
|
|
187
|
+
return;
|
|
188
|
+
}
|
|
189
|
+
|
|
190
|
+
e.preventDefault();
|
|
191
|
+
dropProps.onDrop?.({
|
|
192
|
+
type: "drop",
|
|
193
|
+
x: 0,
|
|
194
|
+
y: 0,
|
|
195
|
+
items,
|
|
196
|
+
dropOperation: "copy",
|
|
197
|
+
});
|
|
198
|
+
};
|
|
199
|
+
|
|
200
|
+
const dropButtonAriaLabel = createMemo(
|
|
201
|
+
() => local["aria-label"] ?? (!local["aria-labelledby"] ? DEFAULT_DROPZONE_LABEL : undefined),
|
|
202
|
+
);
|
|
203
|
+
|
|
204
|
+
return (
|
|
205
|
+
<div
|
|
206
|
+
ref={setDropZoneRef}
|
|
207
|
+
{...filteredDomProps()}
|
|
208
|
+
{...cleanDropProps()}
|
|
209
|
+
{...cleanHoverProps()}
|
|
210
|
+
onClick={onRootClick}
|
|
211
|
+
class={renderProps.class()}
|
|
212
|
+
style={renderProps.style()}
|
|
213
|
+
slot={local.slot}
|
|
214
|
+
data-hovered={isHovered() || undefined}
|
|
215
|
+
data-focused={isFocused() || undefined}
|
|
216
|
+
data-focus-visible={isFocusVisible() || undefined}
|
|
217
|
+
data-drop-target={dropAria.isDropTarget || undefined}
|
|
218
|
+
data-disabled={dropProps.isDisabled || undefined}
|
|
219
|
+
>
|
|
220
|
+
<VisuallyHidden>
|
|
221
|
+
<button
|
|
222
|
+
ref={setDropButtonRef}
|
|
223
|
+
{...cleanDropButtonProps()}
|
|
224
|
+
{...cleanFocusProps()}
|
|
225
|
+
aria-label={dropButtonAriaLabel()}
|
|
226
|
+
aria-labelledby={local["aria-labelledby"]}
|
|
227
|
+
onPaste={onHiddenButtonPaste}
|
|
228
|
+
/>
|
|
229
|
+
</VisuallyHidden>
|
|
230
|
+
{renderProps.renderChildren()}
|
|
231
|
+
</div>
|
|
232
|
+
);
|
|
233
|
+
}
|
|
@@ -0,0 +1,89 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* FieldError primitive for solidaria-components.
|
|
3
|
+
*
|
|
4
|
+
* Displays validation errors for a field from context or explicit validation prop.
|
|
5
|
+
* Port direction: react-aria-components/src/FieldError.tsx
|
|
6
|
+
*/
|
|
7
|
+
|
|
8
|
+
import { type JSX, Show, createContext, createMemo, splitProps, useContext } from "solid-js";
|
|
9
|
+
import { DEFAULT_VALIDATION_RESULT, type ValidationResult } from "@proyecto-viviana/solid-stately";
|
|
10
|
+
import {
|
|
11
|
+
type ClassNameOrFunction,
|
|
12
|
+
type StyleOrFunction,
|
|
13
|
+
type RenderChildren,
|
|
14
|
+
type SlotProps,
|
|
15
|
+
useRenderProps,
|
|
16
|
+
filterDOMProps,
|
|
17
|
+
} from "./utils";
|
|
18
|
+
|
|
19
|
+
export type FieldErrorRenderProps = ValidationResult;
|
|
20
|
+
|
|
21
|
+
export interface FieldErrorContextValue {
|
|
22
|
+
validation: ValidationResult | null;
|
|
23
|
+
errorMessageProps?: JSX.HTMLAttributes<HTMLElement>;
|
|
24
|
+
}
|
|
25
|
+
|
|
26
|
+
export interface FieldErrorProps
|
|
27
|
+
extends Omit<JSX.HTMLAttributes<HTMLElement>, "children" | "class" | "style">, SlotProps {
|
|
28
|
+
/** Validation result. Falls back to context when omitted. */
|
|
29
|
+
validation?: ValidationResult | null;
|
|
30
|
+
/** The children of the component. */
|
|
31
|
+
children?: RenderChildren<FieldErrorRenderProps>;
|
|
32
|
+
/** The CSS className for the element. */
|
|
33
|
+
class?: ClassNameOrFunction<FieldErrorRenderProps>;
|
|
34
|
+
/** The inline style for the element. */
|
|
35
|
+
style?: StyleOrFunction<FieldErrorRenderProps>;
|
|
36
|
+
}
|
|
37
|
+
|
|
38
|
+
export const FieldErrorContext = createContext<ValidationResult | FieldErrorContextValue | null>(
|
|
39
|
+
null,
|
|
40
|
+
);
|
|
41
|
+
|
|
42
|
+
export function FieldError(props: FieldErrorProps): JSX.Element | null {
|
|
43
|
+
const contextValue = useContext(FieldErrorContext);
|
|
44
|
+
const contextValidation = () => {
|
|
45
|
+
if (contextValue && "validation" in contextValue) {
|
|
46
|
+
return contextValue.validation;
|
|
47
|
+
}
|
|
48
|
+
return contextValue;
|
|
49
|
+
};
|
|
50
|
+
const contextErrorMessageProps = () => {
|
|
51
|
+
if (contextValue && "validation" in contextValue) {
|
|
52
|
+
return contextValue.errorMessageProps ?? {};
|
|
53
|
+
}
|
|
54
|
+
return {};
|
|
55
|
+
};
|
|
56
|
+
const [local, domProps] = splitProps(props, ["validation", "children", "class", "style", "slot"]);
|
|
57
|
+
|
|
58
|
+
const validation = createMemo<ValidationResult | null>(
|
|
59
|
+
() => local.validation ?? contextValidation(),
|
|
60
|
+
);
|
|
61
|
+
|
|
62
|
+
const renderProps = useRenderProps(
|
|
63
|
+
{
|
|
64
|
+
children:
|
|
65
|
+
local.children ?? ((currentValidation) => currentValidation.validationErrors.join(" ")),
|
|
66
|
+
class: local.class,
|
|
67
|
+
style: local.style,
|
|
68
|
+
defaultClassName: "solidaria-FieldError",
|
|
69
|
+
},
|
|
70
|
+
() => validation() ?? DEFAULT_VALIDATION_RESULT,
|
|
71
|
+
);
|
|
72
|
+
|
|
73
|
+
const filteredDomProps = filterDOMProps(domProps, { global: true });
|
|
74
|
+
const children = () => renderProps.renderChildren();
|
|
75
|
+
|
|
76
|
+
return (
|
|
77
|
+
<Show when={validation()?.isInvalid && children()}>
|
|
78
|
+
<div
|
|
79
|
+
{...(contextErrorMessageProps() as unknown as JSX.HTMLAttributes<HTMLDivElement>)}
|
|
80
|
+
{...(filteredDomProps as JSX.HTMLAttributes<HTMLDivElement>)}
|
|
81
|
+
slot={local.slot ?? "errorMessage"}
|
|
82
|
+
class={renderProps.class()}
|
|
83
|
+
style={renderProps.style()}
|
|
84
|
+
>
|
|
85
|
+
{children()}
|
|
86
|
+
</div>
|
|
87
|
+
</Show>
|
|
88
|
+
);
|
|
89
|
+
}
|