@proyecto-viviana/solidaria 0.2.4 → 0.2.8
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/dist/actiongroup/createActionGroup.d.ts +29 -0
- package/dist/actiongroup/createActionGroup.d.ts.map +1 -0
- package/dist/actiongroup/index.d.ts +2 -0
- package/dist/actiongroup/index.d.ts.map +1 -0
- package/dist/autocomplete/createAutocomplete.d.ts +6 -2
- package/dist/autocomplete/createAutocomplete.d.ts.map +1 -1
- package/dist/breadcrumbs/createBreadcrumbs.d.ts +2 -0
- package/dist/breadcrumbs/createBreadcrumbs.d.ts.map +1 -1
- package/dist/button/createToggleButtonGroup.d.ts +32 -0
- package/dist/button/createToggleButtonGroup.d.ts.map +1 -0
- package/dist/button/index.d.ts +2 -0
- package/dist/button/index.d.ts.map +1 -1
- package/dist/calendar/createCalendarCell.d.ts +2 -0
- package/dist/calendar/createCalendarCell.d.ts.map +1 -1
- package/dist/calendar/createCalendarGrid.d.ts.map +1 -1
- package/dist/calendar/createRangeCalendarCell.d.ts +3 -1
- package/dist/calendar/createRangeCalendarCell.d.ts.map +1 -1
- package/dist/checkbox/createCheckboxGroup.d.ts +5 -1
- package/dist/checkbox/createCheckboxGroup.d.ts.map +1 -1
- package/dist/collections/index.d.ts +56 -0
- package/dist/collections/index.d.ts.map +1 -0
- package/dist/color/createColorArea.d.ts.map +1 -1
- package/dist/color/createColorSlider.d.ts.map +1 -1
- package/dist/color/createColorWheel.d.ts.map +1 -1
- package/dist/combobox/createComboBox.d.ts +6 -0
- package/dist/combobox/createComboBox.d.ts.map +1 -1
- package/dist/datepicker/createDatePicker.d.ts +6 -0
- package/dist/datepicker/createDatePicker.d.ts.map +1 -1
- package/dist/datepicker/createDateRangePicker.d.ts +40 -0
- package/dist/datepicker/createDateRangePicker.d.ts.map +1 -0
- package/dist/datepicker/createDateSegment.d.ts +1 -1
- package/dist/datepicker/createDateSegment.d.ts.map +1 -1
- package/dist/datepicker/createTimeSegment.d.ts +29 -0
- package/dist/datepicker/createTimeSegment.d.ts.map +1 -0
- package/dist/datepicker/index.d.ts +2 -0
- package/dist/datepicker/index.d.ts.map +1 -1
- package/dist/disclosure/createDisclosureGroup.d.ts +2 -1
- package/dist/disclosure/createDisclosureGroup.d.ts.map +1 -1
- package/dist/dnd/createDrag.d.ts.map +1 -1
- package/dist/dnd/createDraggableCollection.d.ts +4 -0
- package/dist/dnd/createDraggableCollection.d.ts.map +1 -1
- package/dist/dnd/createDraggableItem.d.ts.map +1 -1
- package/dist/dnd/createDrop.d.ts.map +1 -1
- package/dist/dnd/createDroppableCollection.d.ts +32 -1
- package/dist/dnd/createDroppableCollection.d.ts.map +1 -1
- package/dist/dnd/createDroppableItem.d.ts.map +1 -1
- package/dist/dnd/index.d.ts +1 -1
- package/dist/dnd/index.d.ts.map +1 -1
- package/dist/grid/createGrid.d.ts.map +1 -1
- package/dist/gridlist/createGridList.d.ts.map +1 -1
- package/dist/index.d.ts +6 -4
- package/dist/index.d.ts.map +1 -1
- package/dist/index.js +4659 -3452
- package/dist/index.js.map +1 -7
- package/dist/index.ssr.js +4659 -3452
- package/dist/index.ssr.js.map +1 -7
- package/dist/interactions/createFocus.d.ts.map +1 -1
- package/dist/interactions/createFocusWithin.d.ts.map +1 -1
- package/dist/link/createLink.d.ts +10 -0
- package/dist/link/createLink.d.ts.map +1 -1
- package/dist/listbox/createListBox.d.ts +1 -0
- package/dist/listbox/createListBox.d.ts.map +1 -1
- package/dist/listbox/createOption.d.ts.map +1 -1
- package/dist/menu/createMenu.d.ts +1 -0
- package/dist/menu/createMenu.d.ts.map +1 -1
- package/dist/meter/createMeter.d.ts.map +1 -1
- package/dist/numberfield/createNumberField.d.ts +18 -0
- package/dist/numberfield/createNumberField.d.ts.map +1 -1
- package/dist/overlays/createModal.d.ts +16 -0
- package/dist/overlays/createModal.d.ts.map +1 -1
- package/dist/overlays/createOverlay.d.ts.map +1 -1
- package/dist/overlays/index.d.ts +1 -1
- package/dist/overlays/index.d.ts.map +1 -1
- package/dist/popover/createOverlayPosition.d.ts.map +1 -1
- package/dist/popover/createPopover.d.ts.map +1 -1
- package/dist/progress/createProgressBar.d.ts.map +1 -1
- package/dist/radio/createRadioGroup.d.ts +2 -2
- package/dist/radio/createRadioGroup.d.ts.map +1 -1
- package/dist/searchfield/createSearchField.d.ts.map +1 -1
- package/dist/select/createHiddenSelect.d.ts.map +1 -1
- package/dist/select/createSelect.d.ts.map +1 -1
- package/dist/slider/createSlider.d.ts.map +1 -1
- package/dist/table/createTable.d.ts.map +1 -1
- package/dist/tabs/createTabs.d.ts +1 -1
- package/dist/tabs/createTabs.d.ts.map +1 -1
- package/dist/tag/createTag.d.ts.map +1 -1
- package/dist/tag/createTagGroup.d.ts.map +1 -1
- package/dist/toast/createToast.d.ts +4 -0
- package/dist/toast/createToast.d.ts.map +1 -1
- package/dist/toast/createToastRegion.d.ts.map +1 -1
- package/dist/toolbar/createToolbar.d.ts.map +1 -1
- package/dist/tooltip/createTooltipTrigger.d.ts.map +1 -1
- package/dist/tree/createTree.d.ts.map +1 -1
- package/dist/tree/createTreeItem.d.ts.map +1 -1
- package/dist/tree/types.d.ts +4 -0
- package/dist/tree/types.d.ts.map +1 -1
- package/dist/utils/env.d.ts +1 -1
- package/dist/utils/env.d.ts.map +1 -1
- package/dist/utils/platform.d.ts.map +1 -1
- package/dist/visually-hidden/createVisuallyHidden.d.ts.map +1 -1
- package/package.json +8 -6
- package/src/actiongroup/createActionGroup.ts +324 -0
- package/src/actiongroup/index.ts +8 -0
- package/src/autocomplete/createAutocomplete.ts +32 -9
- package/src/breadcrumbs/createBreadcrumbs.ts +10 -15
- package/src/button/createButton.ts +1 -1
- package/src/button/createToggleButtonGroup.ts +128 -0
- package/src/button/index.ts +9 -0
- package/src/calendar/createCalendarCell.ts +6 -4
- package/src/calendar/createCalendarGrid.ts +27 -18
- package/src/calendar/createRangeCalendarCell.ts +26 -9
- package/src/checkbox/createCheckboxGroup.ts +21 -4
- package/src/collections/index.ts +242 -0
- package/src/color/createColorArea.ts +380 -314
- package/src/color/createColorField.ts +137 -137
- package/src/color/createColorSlider.ts +286 -197
- package/src/color/createColorSwatch.ts +40 -40
- package/src/color/createColorWheel.ts +218 -208
- package/src/color/index.ts +24 -24
- package/src/color/types.ts +116 -116
- package/src/combobox/createComboBox.ts +670 -647
- package/src/combobox/index.ts +6 -6
- package/src/datepicker/createDatePicker.ts +54 -16
- package/src/datepicker/createDateRangePicker.ts +246 -0
- package/src/datepicker/createDateSegment.ts +185 -31
- package/src/datepicker/createTimeSegment.ts +370 -0
- package/src/datepicker/index.ts +14 -0
- package/src/dialog/createDialog.ts +120 -120
- package/src/dialog/index.ts +2 -2
- package/src/dialog/types.ts +19 -19
- package/src/disclosure/createDisclosureGroup.ts +5 -2
- package/src/dnd/createDrag.ts +224 -209
- package/src/dnd/createDraggableCollection.ts +96 -63
- package/src/dnd/createDraggableItem.ts +259 -243
- package/src/dnd/createDrop.ts +322 -321
- package/src/dnd/createDroppableCollection.ts +682 -293
- package/src/dnd/createDroppableItem.ts +215 -213
- package/src/dnd/index.ts +55 -47
- package/src/dnd/types.ts +89 -89
- package/src/dnd/utils.ts +294 -294
- package/src/focus/createAutoFocus.ts +321 -321
- package/src/focus/createFocusRestore.ts +313 -313
- package/src/focus/createVirtualFocus.ts +396 -396
- package/src/form/createFormValidation.ts +224 -224
- package/src/form/index.ts +11 -11
- package/src/grid/createGrid.ts +3 -1
- package/src/gridlist/createGridList.ts +16 -0
- package/src/gridlist/createGridListItem.ts +1 -1
- package/src/i18n/NumberFormatter.ts +266 -266
- package/src/i18n/createCollator.ts +79 -79
- package/src/i18n/createDateFormatter.ts +83 -83
- package/src/i18n/createFilter.ts +131 -131
- package/src/i18n/createNumberFormatter.ts +52 -52
- package/src/i18n/index.ts +40 -40
- package/src/i18n/locale.tsx +188 -188
- package/src/i18n/utils.ts +99 -99
- package/src/index.ts +51 -0
- package/src/interactions/createFocus.ts +6 -5
- package/src/interactions/createFocusWithin.ts +6 -5
- package/src/interactions/createLongPress.ts +174 -174
- package/src/interactions/createMove.ts +289 -289
- package/src/interactions/createPress.ts +5 -5
- package/src/landmark/createLandmark.ts +377 -377
- package/src/landmark/index.ts +8 -8
- package/src/link/createLink.ts +23 -8
- package/src/listbox/createListBox.ts +308 -269
- package/src/listbox/createOption.ts +162 -151
- package/src/listbox/index.ts +12 -12
- package/src/live-announcer/announce.ts +322 -322
- package/src/live-announcer/index.ts +9 -9
- package/src/menu/createMenu.ts +405 -396
- package/src/menu/createMenuItem.ts +149 -149
- package/src/menu/createMenuTrigger.ts +88 -88
- package/src/menu/index.ts +18 -18
- package/src/meter/createMeter.ts +1 -6
- package/src/numberfield/createNumberField.ts +311 -268
- package/src/numberfield/index.ts +5 -5
- package/src/overlays/ariaHideOutside.ts +219 -219
- package/src/overlays/createInteractOutside.ts +149 -149
- package/src/overlays/createModal.tsx +238 -202
- package/src/overlays/createOverlay.ts +165 -155
- package/src/overlays/createOverlayTrigger.ts +85 -85
- package/src/overlays/createPreventScroll.ts +266 -266
- package/src/overlays/index.ts +48 -44
- package/src/popover/calculatePosition.ts +6 -6
- package/src/popover/createOverlayPosition.ts +7 -4
- package/src/popover/createPopover.ts +21 -7
- package/src/progress/createProgressBar.ts +6 -1
- package/src/radio/createRadioGroup.ts +88 -14
- package/src/searchfield/createSearchField.ts +241 -186
- package/src/searchfield/index.ts +2 -2
- package/src/select/createHiddenSelect.tsx +263 -236
- package/src/select/createSelect.ts +373 -395
- package/src/select/index.ts +14 -14
- package/src/slider/createSlider.ts +364 -349
- package/src/slider/index.ts +2 -2
- package/src/ssr/index.tsx +370 -370
- package/src/table/createTable.ts +3 -1
- package/src/table/createTableColumnHeader.ts +1 -1
- package/src/table/createTableRow.ts +1 -1
- package/src/tabs/createTabs.ts +80 -51
- package/src/tag/createTag.ts +135 -6
- package/src/tag/createTagGroup.ts +7 -2
- package/src/toast/createToast.ts +8 -2
- package/src/toast/createToastRegion.ts +0 -1
- package/src/toolbar/createToolbar.ts +75 -1
- package/src/tooltip/createTooltip.ts +79 -79
- package/src/tooltip/createTooltipTrigger.ts +226 -222
- package/src/tooltip/index.ts +6 -6
- package/src/tree/createTree.ts +261 -246
- package/src/tree/createTreeItem.ts +282 -233
- package/src/tree/createTreeSelectionCheckbox.ts +68 -68
- package/src/tree/index.ts +16 -16
- package/src/tree/types.ts +91 -87
- package/src/utils/env.ts +55 -54
- package/src/utils/platform.ts +16 -6
- package/src/visually-hidden/createVisuallyHidden.ts +139 -124
- package/src/visually-hidden/index.ts +6 -6
package/src/dnd/utils.ts
CHANGED
|
@@ -1,294 +1,294 @@
|
|
|
1
|
-
/**
|
|
2
|
-
* Drag and Drop utilities for solidaria.
|
|
3
|
-
*/
|
|
4
|
-
|
|
5
|
-
import type {
|
|
6
|
-
DragItem,
|
|
7
|
-
DropItem,
|
|
8
|
-
TextDropItem,
|
|
9
|
-
FileDropItem,
|
|
10
|
-
DirectoryDropItem,
|
|
11
|
-
DropOperation,
|
|
12
|
-
} from '@proyecto-viviana/solid-stately';
|
|
13
|
-
|
|
14
|
-
// Native drag types that can be transferred between applications
|
|
15
|
-
export const NATIVE_DRAG_TYPES: Set<string> = new Set([
|
|
16
|
-
'text/plain',
|
|
17
|
-
'text/uri-list',
|
|
18
|
-
'text/html',
|
|
19
|
-
]);
|
|
20
|
-
|
|
21
|
-
// Custom drag type for serializing multiple items
|
|
22
|
-
export const CUSTOM_DRAG_TYPE = 'application/vnd.solidaria.items+json';
|
|
23
|
-
|
|
24
|
-
// Generic type for unknown file types
|
|
25
|
-
export const GENERIC_TYPE = 'application/octet-stream';
|
|
26
|
-
|
|
27
|
-
// Drop operation bit flags
|
|
28
|
-
export enum DROP_OPERATION {
|
|
29
|
-
none = 0,
|
|
30
|
-
cancel = 0,
|
|
31
|
-
move = 1 << 0,
|
|
32
|
-
copy = 1 << 1,
|
|
33
|
-
link = 1 << 2,
|
|
34
|
-
all = (1 << 0) | (1 << 1) | (1 << 2),
|
|
35
|
-
}
|
|
36
|
-
|
|
37
|
-
// Map from effectAllowed to DROP_OPERATION
|
|
38
|
-
export const DROP_OPERATION_ALLOWED: Record<string, number> = {
|
|
39
|
-
none: DROP_OPERATION.none,
|
|
40
|
-
copy: DROP_OPERATION.copy,
|
|
41
|
-
copyLink: DROP_OPERATION.copy | DROP_OPERATION.link,
|
|
42
|
-
copyMove: DROP_OPERATION.copy | DROP_OPERATION.move,
|
|
43
|
-
link: DROP_OPERATION.link,
|
|
44
|
-
linkMove: DROP_OPERATION.link | DROP_OPERATION.move,
|
|
45
|
-
move: DROP_OPERATION.move,
|
|
46
|
-
all: DROP_OPERATION.all,
|
|
47
|
-
uninitialized: DROP_OPERATION.all,
|
|
48
|
-
};
|
|
49
|
-
|
|
50
|
-
// Map from DROP_OPERATION to effectAllowed
|
|
51
|
-
export const EFFECT_ALLOWED: Record<number, string> = {
|
|
52
|
-
[DROP_OPERATION.none]: 'none',
|
|
53
|
-
[DROP_OPERATION.move]: 'move',
|
|
54
|
-
[DROP_OPERATION.copy]: 'copy',
|
|
55
|
-
[DROP_OPERATION.copy | DROP_OPERATION.move]: 'copyMove',
|
|
56
|
-
[DROP_OPERATION.link]: 'link',
|
|
57
|
-
[DROP_OPERATION.link | DROP_OPERATION.move]: 'linkMove',
|
|
58
|
-
[DROP_OPERATION.copy | DROP_OPERATION.link]: 'copyLink',
|
|
59
|
-
[DROP_OPERATION.all]: 'all',
|
|
60
|
-
};
|
|
61
|
-
|
|
62
|
-
// Map from dropEffect to DropOperation
|
|
63
|
-
export const DROP_EFFECT_TO_DROP_OPERATION: Record<string, DropOperation> = {
|
|
64
|
-
none: 'cancel',
|
|
65
|
-
link: 'link',
|
|
66
|
-
copy: 'copy',
|
|
67
|
-
move: 'move',
|
|
68
|
-
};
|
|
69
|
-
|
|
70
|
-
// Map from DropOperation to dropEffect
|
|
71
|
-
export const DROP_OPERATION_TO_DROP_EFFECT: Record<DropOperation, string> = {
|
|
72
|
-
cancel: 'none',
|
|
73
|
-
link: 'link',
|
|
74
|
-
copy: 'copy',
|
|
75
|
-
move: 'move',
|
|
76
|
-
};
|
|
77
|
-
|
|
78
|
-
/**
|
|
79
|
-
* Get the types present in drag items.
|
|
80
|
-
*/
|
|
81
|
-
export function getTypes(items: DragItem[]): Set<string> {
|
|
82
|
-
const types = new Set<string>();
|
|
83
|
-
for (const item of items) {
|
|
84
|
-
for (const type of Object.keys(item)) {
|
|
85
|
-
types.add(type);
|
|
86
|
-
}
|
|
87
|
-
}
|
|
88
|
-
return types;
|
|
89
|
-
}
|
|
90
|
-
|
|
91
|
-
/**
|
|
92
|
-
* Write drag items to a DataTransfer object.
|
|
93
|
-
*/
|
|
94
|
-
export function writeToDataTransfer(
|
|
95
|
-
dataTransfer: DataTransfer,
|
|
96
|
-
items: DragItem[]
|
|
97
|
-
): void {
|
|
98
|
-
const groupedByType = new Map<string, string[]>();
|
|
99
|
-
let needsCustomData = false;
|
|
100
|
-
const customData: object[] = [];
|
|
101
|
-
|
|
102
|
-
for (const item of items) {
|
|
103
|
-
const types = Object.keys(item);
|
|
104
|
-
if (types.length > 1) {
|
|
105
|
-
needsCustomData = true;
|
|
106
|
-
}
|
|
107
|
-
|
|
108
|
-
const dataByType: Record<string, string> = {};
|
|
109
|
-
for (const type of types) {
|
|
110
|
-
let typeItems = groupedByType.get(type);
|
|
111
|
-
if (!typeItems) {
|
|
112
|
-
typeItems = [];
|
|
113
|
-
groupedByType.set(type, typeItems);
|
|
114
|
-
} else {
|
|
115
|
-
needsCustomData = true;
|
|
116
|
-
}
|
|
117
|
-
|
|
118
|
-
const data = item[type];
|
|
119
|
-
dataByType[type] = data;
|
|
120
|
-
typeItems.push(data);
|
|
121
|
-
}
|
|
122
|
-
|
|
123
|
-
customData.push(dataByType);
|
|
124
|
-
}
|
|
125
|
-
|
|
126
|
-
for (const [type, typeItems] of groupedByType) {
|
|
127
|
-
if (NATIVE_DRAG_TYPES.has(type)) {
|
|
128
|
-
// Join all items of this type with newlines
|
|
129
|
-
const data = typeItems.join('\n');
|
|
130
|
-
dataTransfer.items.add(data, type);
|
|
131
|
-
} else {
|
|
132
|
-
// Set first item for non-native types
|
|
133
|
-
dataTransfer.items.add(typeItems[0], type);
|
|
134
|
-
}
|
|
135
|
-
}
|
|
136
|
-
|
|
137
|
-
if (needsCustomData) {
|
|
138
|
-
const data = JSON.stringify(customData);
|
|
139
|
-
dataTransfer.items.add(data, CUSTOM_DRAG_TYPE);
|
|
140
|
-
}
|
|
141
|
-
}
|
|
142
|
-
|
|
143
|
-
/**
|
|
144
|
-
* Read drop items from a DataTransfer object.
|
|
145
|
-
*/
|
|
146
|
-
export function readFromDataTransfer(dataTransfer: DataTransfer): DropItem[] {
|
|
147
|
-
const items: DropItem[] = [];
|
|
148
|
-
|
|
149
|
-
if (!dataTransfer) {
|
|
150
|
-
return items;
|
|
151
|
-
}
|
|
152
|
-
|
|
153
|
-
// Check for custom drag type first
|
|
154
|
-
let hasCustomType = false;
|
|
155
|
-
if (dataTransfer.types.includes(CUSTOM_DRAG_TYPE)) {
|
|
156
|
-
try {
|
|
157
|
-
const data = dataTransfer.getData(CUSTOM_DRAG_TYPE);
|
|
158
|
-
const parsed = JSON.parse(data);
|
|
159
|
-
for (const item of parsed) {
|
|
160
|
-
items.push({
|
|
161
|
-
kind: 'text',
|
|
162
|
-
types: new Set(Object.keys(item)),
|
|
163
|
-
getText: (type) => Promise.resolve(item[type]),
|
|
164
|
-
});
|
|
165
|
-
}
|
|
166
|
-
hasCustomType = true;
|
|
167
|
-
} catch {
|
|
168
|
-
// ignore parsing errors
|
|
169
|
-
}
|
|
170
|
-
}
|
|
171
|
-
|
|
172
|
-
// Fall back to native items
|
|
173
|
-
if (!hasCustomType) {
|
|
174
|
-
const stringItems = new Map<string, string>();
|
|
175
|
-
|
|
176
|
-
for (const item of dataTransfer.items) {
|
|
177
|
-
if (item.kind === 'string') {
|
|
178
|
-
const type = item.type || GENERIC_TYPE;
|
|
179
|
-
stringItems.set(type, dataTransfer.getData(item.type));
|
|
180
|
-
} else if (item.kind === 'file') {
|
|
181
|
-
const file = item.getAsFile();
|
|
182
|
-
if (file) {
|
|
183
|
-
items.push(createFileItem(file));
|
|
184
|
-
}
|
|
185
|
-
}
|
|
186
|
-
}
|
|
187
|
-
|
|
188
|
-
if (stringItems.size > 0) {
|
|
189
|
-
items.push({
|
|
190
|
-
kind: 'text',
|
|
191
|
-
types: new Set(stringItems.keys()),
|
|
192
|
-
getText: (type) => Promise.resolve(stringItems.get(type) ?? ''),
|
|
193
|
-
});
|
|
194
|
-
}
|
|
195
|
-
}
|
|
196
|
-
|
|
197
|
-
return items;
|
|
198
|
-
}
|
|
199
|
-
|
|
200
|
-
/**
|
|
201
|
-
* Create a FileDropItem from a File object.
|
|
202
|
-
*/
|
|
203
|
-
function createFileItem(file: File): FileDropItem {
|
|
204
|
-
return {
|
|
205
|
-
kind: 'file',
|
|
206
|
-
type: file.type || GENERIC_TYPE,
|
|
207
|
-
name: file.name,
|
|
208
|
-
getText: () => file.text(),
|
|
209
|
-
getFile: () => Promise.resolve(file),
|
|
210
|
-
};
|
|
211
|
-
}
|
|
212
|
-
|
|
213
|
-
/**
|
|
214
|
-
* DragTypes implementation for checking drag types.
|
|
215
|
-
*/
|
|
216
|
-
export class DragTypesImpl {
|
|
217
|
-
private types: Set<string>;
|
|
218
|
-
private includesUnknownTypes: boolean;
|
|
219
|
-
|
|
220
|
-
constructor(dataTransfer: DataTransfer) {
|
|
221
|
-
this.types = new Set<string>();
|
|
222
|
-
let hasFiles = false;
|
|
223
|
-
|
|
224
|
-
for (const item of dataTransfer.items) {
|
|
225
|
-
if (item.type !== CUSTOM_DRAG_TYPE) {
|
|
226
|
-
if (item.kind === 'file') {
|
|
227
|
-
hasFiles = true;
|
|
228
|
-
}
|
|
229
|
-
if (item.type) {
|
|
230
|
-
this.types.add(item.type);
|
|
231
|
-
} else {
|
|
232
|
-
this.types.add(GENERIC_TYPE);
|
|
233
|
-
}
|
|
234
|
-
}
|
|
235
|
-
}
|
|
236
|
-
|
|
237
|
-
// Safari doesn't expose file types until drop
|
|
238
|
-
this.includesUnknownTypes =
|
|
239
|
-
!hasFiles && dataTransfer.types.includes('Files');
|
|
240
|
-
}
|
|
241
|
-
|
|
242
|
-
has(type: string | symbol): boolean {
|
|
243
|
-
if (
|
|
244
|
-
this.includesUnknownTypes ||
|
|
245
|
-
(typeof type === 'symbol' && this.types.has(GENERIC_TYPE))
|
|
246
|
-
) {
|
|
247
|
-
return true;
|
|
248
|
-
}
|
|
249
|
-
return typeof type === 'string' && this.types.has(type);
|
|
250
|
-
}
|
|
251
|
-
}
|
|
252
|
-
|
|
253
|
-
/**
|
|
254
|
-
* Check if a drop item is a text item.
|
|
255
|
-
*/
|
|
256
|
-
export function isTextDropItem(dropItem: DropItem): dropItem is TextDropItem {
|
|
257
|
-
return dropItem.kind === 'text';
|
|
258
|
-
}
|
|
259
|
-
|
|
260
|
-
/**
|
|
261
|
-
* Check if a drop item is a file item.
|
|
262
|
-
*/
|
|
263
|
-
export function isFileDropItem(dropItem: DropItem): dropItem is FileDropItem {
|
|
264
|
-
return dropItem.kind === 'file';
|
|
265
|
-
}
|
|
266
|
-
|
|
267
|
-
/**
|
|
268
|
-
* Check if a drop item is a directory item.
|
|
269
|
-
*/
|
|
270
|
-
export function isDirectoryDropItem(
|
|
271
|
-
dropItem: DropItem
|
|
272
|
-
): dropItem is DirectoryDropItem {
|
|
273
|
-
return dropItem.kind === 'directory';
|
|
274
|
-
}
|
|
275
|
-
|
|
276
|
-
// Global state for tracking drag operations
|
|
277
|
-
let globalDropEffect: string | undefined;
|
|
278
|
-
let globalAllowedDropOperations: number = DROP_OPERATION.none;
|
|
279
|
-
|
|
280
|
-
export function setGlobalDropEffect(effect: string | undefined): void {
|
|
281
|
-
globalDropEffect = effect;
|
|
282
|
-
}
|
|
283
|
-
|
|
284
|
-
export function getGlobalDropEffect(): string | undefined {
|
|
285
|
-
return globalDropEffect;
|
|
286
|
-
}
|
|
287
|
-
|
|
288
|
-
export function setGlobalAllowedDropOperations(ops: number): void {
|
|
289
|
-
globalAllowedDropOperations = ops;
|
|
290
|
-
}
|
|
291
|
-
|
|
292
|
-
export function getGlobalAllowedDropOperations(): number {
|
|
293
|
-
return globalAllowedDropOperations;
|
|
294
|
-
}
|
|
1
|
+
/**
|
|
2
|
+
* Drag and Drop utilities for solidaria.
|
|
3
|
+
*/
|
|
4
|
+
|
|
5
|
+
import type {
|
|
6
|
+
DragItem,
|
|
7
|
+
DropItem,
|
|
8
|
+
TextDropItem,
|
|
9
|
+
FileDropItem,
|
|
10
|
+
DirectoryDropItem,
|
|
11
|
+
DropOperation,
|
|
12
|
+
} from '@proyecto-viviana/solid-stately';
|
|
13
|
+
|
|
14
|
+
// Native drag types that can be transferred between applications
|
|
15
|
+
export const NATIVE_DRAG_TYPES: Set<string> = new Set([
|
|
16
|
+
'text/plain',
|
|
17
|
+
'text/uri-list',
|
|
18
|
+
'text/html',
|
|
19
|
+
]);
|
|
20
|
+
|
|
21
|
+
// Custom drag type for serializing multiple items
|
|
22
|
+
export const CUSTOM_DRAG_TYPE = 'application/vnd.solidaria.items+json';
|
|
23
|
+
|
|
24
|
+
// Generic type for unknown file types
|
|
25
|
+
export const GENERIC_TYPE = 'application/octet-stream';
|
|
26
|
+
|
|
27
|
+
// Drop operation bit flags
|
|
28
|
+
export enum DROP_OPERATION {
|
|
29
|
+
none = 0,
|
|
30
|
+
cancel = 0,
|
|
31
|
+
move = 1 << 0,
|
|
32
|
+
copy = 1 << 1,
|
|
33
|
+
link = 1 << 2,
|
|
34
|
+
all = (1 << 0) | (1 << 1) | (1 << 2),
|
|
35
|
+
}
|
|
36
|
+
|
|
37
|
+
// Map from effectAllowed to DROP_OPERATION
|
|
38
|
+
export const DROP_OPERATION_ALLOWED: Record<string, number> = {
|
|
39
|
+
none: DROP_OPERATION.none,
|
|
40
|
+
copy: DROP_OPERATION.copy,
|
|
41
|
+
copyLink: DROP_OPERATION.copy | DROP_OPERATION.link,
|
|
42
|
+
copyMove: DROP_OPERATION.copy | DROP_OPERATION.move,
|
|
43
|
+
link: DROP_OPERATION.link,
|
|
44
|
+
linkMove: DROP_OPERATION.link | DROP_OPERATION.move,
|
|
45
|
+
move: DROP_OPERATION.move,
|
|
46
|
+
all: DROP_OPERATION.all,
|
|
47
|
+
uninitialized: DROP_OPERATION.all,
|
|
48
|
+
};
|
|
49
|
+
|
|
50
|
+
// Map from DROP_OPERATION to effectAllowed
|
|
51
|
+
export const EFFECT_ALLOWED: Record<number, string> = {
|
|
52
|
+
[DROP_OPERATION.none]: 'none',
|
|
53
|
+
[DROP_OPERATION.move]: 'move',
|
|
54
|
+
[DROP_OPERATION.copy]: 'copy',
|
|
55
|
+
[DROP_OPERATION.copy | DROP_OPERATION.move]: 'copyMove',
|
|
56
|
+
[DROP_OPERATION.link]: 'link',
|
|
57
|
+
[DROP_OPERATION.link | DROP_OPERATION.move]: 'linkMove',
|
|
58
|
+
[DROP_OPERATION.copy | DROP_OPERATION.link]: 'copyLink',
|
|
59
|
+
[DROP_OPERATION.all]: 'all',
|
|
60
|
+
};
|
|
61
|
+
|
|
62
|
+
// Map from dropEffect to DropOperation
|
|
63
|
+
export const DROP_EFFECT_TO_DROP_OPERATION: Record<string, DropOperation> = {
|
|
64
|
+
none: 'cancel',
|
|
65
|
+
link: 'link',
|
|
66
|
+
copy: 'copy',
|
|
67
|
+
move: 'move',
|
|
68
|
+
};
|
|
69
|
+
|
|
70
|
+
// Map from DropOperation to dropEffect
|
|
71
|
+
export const DROP_OPERATION_TO_DROP_EFFECT: Record<DropOperation, string> = {
|
|
72
|
+
cancel: 'none',
|
|
73
|
+
link: 'link',
|
|
74
|
+
copy: 'copy',
|
|
75
|
+
move: 'move',
|
|
76
|
+
};
|
|
77
|
+
|
|
78
|
+
/**
|
|
79
|
+
* Get the types present in drag items.
|
|
80
|
+
*/
|
|
81
|
+
export function getTypes(items: DragItem[]): Set<string> {
|
|
82
|
+
const types = new Set<string>();
|
|
83
|
+
for (const item of items) {
|
|
84
|
+
for (const type of Object.keys(item)) {
|
|
85
|
+
types.add(type);
|
|
86
|
+
}
|
|
87
|
+
}
|
|
88
|
+
return types;
|
|
89
|
+
}
|
|
90
|
+
|
|
91
|
+
/**
|
|
92
|
+
* Write drag items to a DataTransfer object.
|
|
93
|
+
*/
|
|
94
|
+
export function writeToDataTransfer(
|
|
95
|
+
dataTransfer: DataTransfer,
|
|
96
|
+
items: DragItem[]
|
|
97
|
+
): void {
|
|
98
|
+
const groupedByType = new Map<string, string[]>();
|
|
99
|
+
let needsCustomData = false;
|
|
100
|
+
const customData: object[] = [];
|
|
101
|
+
|
|
102
|
+
for (const item of items) {
|
|
103
|
+
const types = Object.keys(item);
|
|
104
|
+
if (types.length > 1) {
|
|
105
|
+
needsCustomData = true;
|
|
106
|
+
}
|
|
107
|
+
|
|
108
|
+
const dataByType: Record<string, string> = {};
|
|
109
|
+
for (const type of types) {
|
|
110
|
+
let typeItems = groupedByType.get(type);
|
|
111
|
+
if (!typeItems) {
|
|
112
|
+
typeItems = [];
|
|
113
|
+
groupedByType.set(type, typeItems);
|
|
114
|
+
} else {
|
|
115
|
+
needsCustomData = true;
|
|
116
|
+
}
|
|
117
|
+
|
|
118
|
+
const data = item[type];
|
|
119
|
+
dataByType[type] = data;
|
|
120
|
+
typeItems.push(data);
|
|
121
|
+
}
|
|
122
|
+
|
|
123
|
+
customData.push(dataByType);
|
|
124
|
+
}
|
|
125
|
+
|
|
126
|
+
for (const [type, typeItems] of groupedByType) {
|
|
127
|
+
if (NATIVE_DRAG_TYPES.has(type)) {
|
|
128
|
+
// Join all items of this type with newlines
|
|
129
|
+
const data = typeItems.join('\n');
|
|
130
|
+
dataTransfer.items.add(data, type);
|
|
131
|
+
} else {
|
|
132
|
+
// Set first item for non-native types
|
|
133
|
+
dataTransfer.items.add(typeItems[0], type);
|
|
134
|
+
}
|
|
135
|
+
}
|
|
136
|
+
|
|
137
|
+
if (needsCustomData) {
|
|
138
|
+
const data = JSON.stringify(customData);
|
|
139
|
+
dataTransfer.items.add(data, CUSTOM_DRAG_TYPE);
|
|
140
|
+
}
|
|
141
|
+
}
|
|
142
|
+
|
|
143
|
+
/**
|
|
144
|
+
* Read drop items from a DataTransfer object.
|
|
145
|
+
*/
|
|
146
|
+
export function readFromDataTransfer(dataTransfer: DataTransfer): DropItem[] {
|
|
147
|
+
const items: DropItem[] = [];
|
|
148
|
+
|
|
149
|
+
if (!dataTransfer) {
|
|
150
|
+
return items;
|
|
151
|
+
}
|
|
152
|
+
|
|
153
|
+
// Check for custom drag type first
|
|
154
|
+
let hasCustomType = false;
|
|
155
|
+
if (dataTransfer.types.includes(CUSTOM_DRAG_TYPE)) {
|
|
156
|
+
try {
|
|
157
|
+
const data = dataTransfer.getData(CUSTOM_DRAG_TYPE);
|
|
158
|
+
const parsed = JSON.parse(data);
|
|
159
|
+
for (const item of parsed) {
|
|
160
|
+
items.push({
|
|
161
|
+
kind: 'text',
|
|
162
|
+
types: new Set(Object.keys(item)),
|
|
163
|
+
getText: (type) => Promise.resolve(item[type]),
|
|
164
|
+
});
|
|
165
|
+
}
|
|
166
|
+
hasCustomType = true;
|
|
167
|
+
} catch {
|
|
168
|
+
// ignore parsing errors
|
|
169
|
+
}
|
|
170
|
+
}
|
|
171
|
+
|
|
172
|
+
// Fall back to native items
|
|
173
|
+
if (!hasCustomType) {
|
|
174
|
+
const stringItems = new Map<string, string>();
|
|
175
|
+
|
|
176
|
+
for (const item of dataTransfer.items) {
|
|
177
|
+
if (item.kind === 'string') {
|
|
178
|
+
const type = item.type || GENERIC_TYPE;
|
|
179
|
+
stringItems.set(type, dataTransfer.getData(item.type));
|
|
180
|
+
} else if (item.kind === 'file') {
|
|
181
|
+
const file = item.getAsFile();
|
|
182
|
+
if (file) {
|
|
183
|
+
items.push(createFileItem(file));
|
|
184
|
+
}
|
|
185
|
+
}
|
|
186
|
+
}
|
|
187
|
+
|
|
188
|
+
if (stringItems.size > 0) {
|
|
189
|
+
items.push({
|
|
190
|
+
kind: 'text',
|
|
191
|
+
types: new Set(stringItems.keys()),
|
|
192
|
+
getText: (type) => Promise.resolve(stringItems.get(type) ?? ''),
|
|
193
|
+
});
|
|
194
|
+
}
|
|
195
|
+
}
|
|
196
|
+
|
|
197
|
+
return items;
|
|
198
|
+
}
|
|
199
|
+
|
|
200
|
+
/**
|
|
201
|
+
* Create a FileDropItem from a File object.
|
|
202
|
+
*/
|
|
203
|
+
function createFileItem(file: File): FileDropItem {
|
|
204
|
+
return {
|
|
205
|
+
kind: 'file',
|
|
206
|
+
type: file.type || GENERIC_TYPE,
|
|
207
|
+
name: file.name,
|
|
208
|
+
getText: () => file.text(),
|
|
209
|
+
getFile: () => Promise.resolve(file),
|
|
210
|
+
};
|
|
211
|
+
}
|
|
212
|
+
|
|
213
|
+
/**
|
|
214
|
+
* DragTypes implementation for checking drag types.
|
|
215
|
+
*/
|
|
216
|
+
export class DragTypesImpl {
|
|
217
|
+
private types: Set<string>;
|
|
218
|
+
private includesUnknownTypes: boolean;
|
|
219
|
+
|
|
220
|
+
constructor(dataTransfer: DataTransfer) {
|
|
221
|
+
this.types = new Set<string>();
|
|
222
|
+
let hasFiles = false;
|
|
223
|
+
|
|
224
|
+
for (const item of dataTransfer.items) {
|
|
225
|
+
if (item.type !== CUSTOM_DRAG_TYPE) {
|
|
226
|
+
if (item.kind === 'file') {
|
|
227
|
+
hasFiles = true;
|
|
228
|
+
}
|
|
229
|
+
if (item.type) {
|
|
230
|
+
this.types.add(item.type);
|
|
231
|
+
} else {
|
|
232
|
+
this.types.add(GENERIC_TYPE);
|
|
233
|
+
}
|
|
234
|
+
}
|
|
235
|
+
}
|
|
236
|
+
|
|
237
|
+
// Safari doesn't expose file types until drop
|
|
238
|
+
this.includesUnknownTypes =
|
|
239
|
+
!hasFiles && dataTransfer.types.includes('Files');
|
|
240
|
+
}
|
|
241
|
+
|
|
242
|
+
has(type: string | symbol): boolean {
|
|
243
|
+
if (
|
|
244
|
+
this.includesUnknownTypes ||
|
|
245
|
+
(typeof type === 'symbol' && this.types.has(GENERIC_TYPE))
|
|
246
|
+
) {
|
|
247
|
+
return true;
|
|
248
|
+
}
|
|
249
|
+
return typeof type === 'string' && this.types.has(type);
|
|
250
|
+
}
|
|
251
|
+
}
|
|
252
|
+
|
|
253
|
+
/**
|
|
254
|
+
* Check if a drop item is a text item.
|
|
255
|
+
*/
|
|
256
|
+
export function isTextDropItem(dropItem: DropItem): dropItem is TextDropItem {
|
|
257
|
+
return dropItem.kind === 'text';
|
|
258
|
+
}
|
|
259
|
+
|
|
260
|
+
/**
|
|
261
|
+
* Check if a drop item is a file item.
|
|
262
|
+
*/
|
|
263
|
+
export function isFileDropItem(dropItem: DropItem): dropItem is FileDropItem {
|
|
264
|
+
return dropItem.kind === 'file';
|
|
265
|
+
}
|
|
266
|
+
|
|
267
|
+
/**
|
|
268
|
+
* Check if a drop item is a directory item.
|
|
269
|
+
*/
|
|
270
|
+
export function isDirectoryDropItem(
|
|
271
|
+
dropItem: DropItem
|
|
272
|
+
): dropItem is DirectoryDropItem {
|
|
273
|
+
return dropItem.kind === 'directory';
|
|
274
|
+
}
|
|
275
|
+
|
|
276
|
+
// Global state for tracking drag operations
|
|
277
|
+
let globalDropEffect: string | undefined;
|
|
278
|
+
let globalAllowedDropOperations: number = DROP_OPERATION.none;
|
|
279
|
+
|
|
280
|
+
export function setGlobalDropEffect(effect: string | undefined): void {
|
|
281
|
+
globalDropEffect = effect;
|
|
282
|
+
}
|
|
283
|
+
|
|
284
|
+
export function getGlobalDropEffect(): string | undefined {
|
|
285
|
+
return globalDropEffect;
|
|
286
|
+
}
|
|
287
|
+
|
|
288
|
+
export function setGlobalAllowedDropOperations(ops: number): void {
|
|
289
|
+
globalAllowedDropOperations = ops;
|
|
290
|
+
}
|
|
291
|
+
|
|
292
|
+
export function getGlobalAllowedDropOperations(): number {
|
|
293
|
+
return globalAllowedDropOperations;
|
|
294
|
+
}
|