@r2digisolutions/components 0.1.6 → 0.1.7
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/README.md +1 -1
- package/dist/components/atoms/Checkbox/Checkbox.svelte +10 -3
- package/dist/components/atoms/Checkbox/Checkbox.svelte.d.ts +3 -0
- package/dist/components/atoms/Input/Input.svelte +17 -2
- package/dist/components/atoms/Input/Input.svelte.d.ts +6 -1
- package/dist/components/atoms/MarqueeRect/MarqueeRect.svelte +21 -0
- package/dist/components/atoms/MarqueeRect/MarqueeRect.svelte.d.ts +8 -0
- package/dist/components/atoms/Textarea/Textarea.svelte +4 -1
- package/dist/components/atoms/Textarea/Textarea.svelte.d.ts +1 -0
- package/dist/components/atoms/Toggle/Toggle.svelte +1 -1
- package/dist/components/molecules/BulkActionBar/BulkActionBar.svelte +19 -5
- package/dist/components/molecules/CodeEditor/CodeEditor.svelte +13 -10
- package/dist/components/molecules/ColorPicker/ColorPicker.svelte +166 -96
- package/dist/components/molecules/ConditionalFormatPanel/ConditionalFormatPanel.stories.d.ts +9 -0
- package/dist/components/molecules/ConditionalFormatPanel/ConditionalFormatPanel.stories.js +8 -0
- package/dist/components/molecules/ConditionalFormatPanel/ConditionalFormatPanel.svelte +412 -0
- package/dist/components/molecules/ConditionalFormatPanel/ConditionalFormatPanel.svelte.d.ts +14 -0
- package/dist/components/molecules/ConditionalFormatPanel/ConditionalFormatPanelStory.svelte +27 -0
- package/dist/components/molecules/ConditionalFormatPanel/ConditionalFormatPanelStory.svelte.d.ts +3 -0
- package/dist/components/molecules/ContextMenu/ContextMenu.svelte +73 -21
- package/dist/components/molecules/ContextMenu/ContextMenu.svelte.d.ts +8 -1
- package/dist/components/molecules/DateTimePicker/DateTimePicker.svelte.d.ts +1 -1
- package/dist/components/molecules/FormDateTimePicker/FormDateTimePicker.svelte.d.ts +1 -1
- package/dist/components/molecules/Gauge/Gauge.stories.d.ts +1 -1
- package/dist/components/molecules/InfiniteScroll/InfiniteScroll.stories.d.ts +1 -1
- package/dist/components/organisms/AssetPickerPage/AssetPickerPage.svelte.d.ts +1 -1
- package/dist/components/organisms/BacklogPage/BacklogPage.svelte.d.ts +1 -1
- package/dist/components/organisms/CalendarApp/CalendarApp.svelte.d.ts +1 -1
- package/dist/components/organisms/DataGrid/DataGrid.stories.d.ts +65 -0
- package/dist/components/organisms/DataGrid/DataGrid.stories.js +95 -0
- package/dist/components/organisms/DataGrid/DataGrid.svelte +2264 -0
- package/dist/components/organisms/DataGrid/DataGrid.svelte.d.ts +99 -0
- package/dist/components/organisms/DataGrid/DataGridStory.svelte +659 -0
- package/dist/components/organisms/DataGrid/DataGridStory.svelte.d.ts +11 -0
- package/dist/components/organisms/DataGrid/breakpoints.d.ts +10 -0
- package/dist/components/organisms/DataGrid/breakpoints.js +20 -0
- package/dist/components/organisms/DataGrid/cellEditors.d.ts +8 -0
- package/dist/components/organisms/DataGrid/cellEditors.js +59 -0
- package/dist/components/organisms/DataGrid/conditionalFormat.d.ts +11 -0
- package/dist/components/organisms/DataGrid/conditionalFormat.js +98 -0
- package/dist/components/organisms/DataGrid/filterRows.d.ts +5 -0
- package/dist/components/organisms/DataGrid/filterRows.js +60 -0
- package/dist/components/organisms/DataGrid/marks.d.ts +9 -0
- package/dist/components/organisms/DataGrid/marks.js +91 -0
- package/dist/components/organisms/DataGrid/types.d.ts +126 -0
- package/dist/components/organisms/DataGrid/types.js +21 -0
- package/dist/components/organisms/ResourceStudio/ResourceStudio.stories.d.ts +33 -0
- package/dist/components/organisms/ResourceStudio/ResourceStudio.stories.js +56 -0
- package/dist/components/organisms/ResourceStudio/ResourceStudio.svelte +830 -0
- package/dist/components/organisms/ResourceStudio/ResourceStudio.svelte.d.ts +68 -0
- package/dist/components/organisms/ResourceStudio/ResourceStudioStory.svelte +600 -0
- package/dist/components/organisms/ResourceStudio/ResourceStudioStory.svelte.d.ts +7 -0
- package/dist/components/organisms/ResourceStudio/fieldsToColumns.d.ts +4 -0
- package/dist/components/organisms/ResourceStudio/fieldsToColumns.js +20 -0
- package/dist/components/organisms/ResourceStudio/fieldsToSchema.d.ts +6 -0
- package/dist/components/organisms/ResourceStudio/fieldsToSchema.js +53 -0
- package/dist/components/organisms/ResourceStudio/types.d.ts +69 -0
- package/dist/components/organisms/ResourceStudio/types.js +15 -0
- package/dist/components/organisms/Scheduler/Scheduler.svelte.d.ts +1 -1
- package/dist/components/organisms/SchemaForm/SchemaForm.svelte +10 -3
- package/dist/components/organisms/SchemaForm/SchemaForm.svelte.d.ts +1 -0
- package/dist/components/templates/ResourceStudioTemplate/ResourceStudioTemplate.stories.d.ts +25 -0
- package/dist/components/templates/ResourceStudioTemplate/ResourceStudioTemplate.stories.js +18 -0
- package/dist/components/templates/ResourceStudioTemplate/ResourceStudioTemplate.svelte +192 -0
- package/dist/components/templates/ResourceStudioTemplate/ResourceStudioTemplate.svelte.d.ts +62 -0
- package/dist/components/templates/ResourceStudioTemplate/ResourceStudioTemplateStory.svelte +129 -0
- package/dist/components/templates/ResourceStudioTemplate/ResourceStudioTemplateStory.svelte.d.ts +7 -0
- package/dist/index.d.ts +11 -0
- package/dist/index.js +8 -0
- package/dist/utils/marqueeSelect.d.ts +48 -0
- package/dist/utils/marqueeSelect.js +189 -0
- package/package.json +1 -1
|
@@ -0,0 +1,129 @@
|
|
|
1
|
+
<script lang="ts">
|
|
2
|
+
import ResourceStudioTemplate from './ResourceStudioTemplate.svelte';
|
|
3
|
+
import type { ResourceDefinition } from '../../organisms/ResourceStudio/types.js';
|
|
4
|
+
import Badge from '../../atoms/Badge/Badge.svelte';
|
|
5
|
+
import Button from '../../atoms/Button/Button.svelte';
|
|
6
|
+
import CodeEditor from '../../molecules/CodeEditor/CodeEditor.svelte';
|
|
7
|
+
|
|
8
|
+
type Example = 'crud' | 'sql' | 'mainOnly';
|
|
9
|
+
|
|
10
|
+
let { example = 'crud' }: { example?: Example } = $props();
|
|
11
|
+
|
|
12
|
+
const resources = $derived.by((): ResourceDefinition[] => {
|
|
13
|
+
const sql = example === 'sql';
|
|
14
|
+
return [
|
|
15
|
+
{
|
|
16
|
+
id: 'users',
|
|
17
|
+
name: sql ? 'users' : 'Users',
|
|
18
|
+
group: sql ? 'public' : 'Auth',
|
|
19
|
+
recordCount: 3,
|
|
20
|
+
fields: [
|
|
21
|
+
{ id: 'id', label: 'ID', type: 'string', readonly: true },
|
|
22
|
+
{ id: 'name', label: 'Name', type: 'string', required: true },
|
|
23
|
+
{ id: 'email', label: 'Email', type: 'string', required: true },
|
|
24
|
+
{
|
|
25
|
+
id: 'role',
|
|
26
|
+
label: 'Role',
|
|
27
|
+
type: 'enum',
|
|
28
|
+
options: [
|
|
29
|
+
{ value: 'admin', label: 'Admin' },
|
|
30
|
+
{ value: 'editor', label: 'Editor' }
|
|
31
|
+
]
|
|
32
|
+
}
|
|
33
|
+
]
|
|
34
|
+
},
|
|
35
|
+
{
|
|
36
|
+
id: 'orders',
|
|
37
|
+
name: sql ? 'orders' : 'Orders',
|
|
38
|
+
group: sql ? 'public' : 'Commerce',
|
|
39
|
+
recordCount: 3,
|
|
40
|
+
fields: [
|
|
41
|
+
{ id: 'id', label: 'ID', type: 'string', readonly: true },
|
|
42
|
+
{
|
|
43
|
+
id: 'status',
|
|
44
|
+
label: 'Status',
|
|
45
|
+
type: 'enum',
|
|
46
|
+
options: [
|
|
47
|
+
{ value: 'paid', label: 'Paid' },
|
|
48
|
+
{ value: 'pending', label: 'Pending' }
|
|
49
|
+
]
|
|
50
|
+
},
|
|
51
|
+
{ id: 'total', label: 'Total', type: 'number' }
|
|
52
|
+
]
|
|
53
|
+
}
|
|
54
|
+
];
|
|
55
|
+
});
|
|
56
|
+
|
|
57
|
+
let activeResourceId = $state('users');
|
|
58
|
+
let records = $state<Record<string, unknown>[]>([
|
|
59
|
+
{ id: '1', name: 'Ana', email: 'ana@r2.dev', role: 'admin' },
|
|
60
|
+
{ id: '2', name: 'Carlos', email: 'carlos@r2.dev', role: 'editor' },
|
|
61
|
+
{ id: '3', name: 'Maya', email: 'maya@r2.dev', role: 'editor' }
|
|
62
|
+
]);
|
|
63
|
+
let orderRecords = $state<Record<string, unknown>[]>([
|
|
64
|
+
{ id: 'o1', status: 'paid', total: 120 },
|
|
65
|
+
{ id: 'o2', status: 'pending', total: 80 },
|
|
66
|
+
{ id: 'o3', status: 'paid', total: 440 }
|
|
67
|
+
]);
|
|
68
|
+
let sqlText = $state('select * from users;');
|
|
69
|
+
|
|
70
|
+
$effect(() => {
|
|
71
|
+
// Only seed when the Storybook example changes.
|
|
72
|
+
activeResourceId = example === 'mainOnly' ? 'orders' : 'users';
|
|
73
|
+
});
|
|
74
|
+
|
|
75
|
+
const activeRecords = $derived(
|
|
76
|
+
activeResourceId === 'orders' ? orderRecords : records
|
|
77
|
+
);
|
|
78
|
+
</script>
|
|
79
|
+
|
|
80
|
+
<ResourceStudioTemplate
|
|
81
|
+
title={example === 'sql' ? 'Database Studio' : 'Admin'}
|
|
82
|
+
description={example === 'sql'
|
|
83
|
+
? 'Drizzle-like browse UI built on ResourceStudio.'
|
|
84
|
+
: 'Full-page CRUD shell for your collections.'}
|
|
85
|
+
{resources}
|
|
86
|
+
bind:activeResourceId
|
|
87
|
+
records={activeRecords}
|
|
88
|
+
totalRecords={activeRecords.length}
|
|
89
|
+
layout={example === 'mainOnly' ? 'main-only' : 'sidebar-main-detail'}
|
|
90
|
+
modes={example === 'sql' ? ['browse', 'schema', 'query', 'detail'] : ['browse', 'detail', 'schema']}
|
|
91
|
+
labels={example === 'sql'
|
|
92
|
+
? { resources: 'Tables', records: 'rows', addRecord: 'Insert row', query: 'SQL' }
|
|
93
|
+
: undefined}
|
|
94
|
+
oninsert={(row) => {
|
|
95
|
+
if (activeResourceId === 'orders') orderRecords = [row, ...orderRecords];
|
|
96
|
+
else records = [row, ...records];
|
|
97
|
+
}}
|
|
98
|
+
onupdate={(id, patch) => {
|
|
99
|
+
const apply = (list: Record<string, unknown>[]) =>
|
|
100
|
+
list.map((r) => (String(r.id) === id ? { ...r, ...patch } : r));
|
|
101
|
+
if (activeResourceId === 'orders') orderRecords = apply(orderRecords);
|
|
102
|
+
else records = apply(records);
|
|
103
|
+
}}
|
|
104
|
+
ondelete={(ids) => {
|
|
105
|
+
const filter = (list: Record<string, unknown>[]) =>
|
|
106
|
+
list.filter((r) => !ids.includes(String(r.id)));
|
|
107
|
+
if (activeResourceId === 'orders') orderRecords = filter(orderRecords);
|
|
108
|
+
else records = filter(records);
|
|
109
|
+
}}
|
|
110
|
+
>
|
|
111
|
+
{#snippet headerActions()}
|
|
112
|
+
<Button size="sm" variant="secondary">Docs</Button>
|
|
113
|
+
{/snippet}
|
|
114
|
+
|
|
115
|
+
{#snippet queryPanel()}
|
|
116
|
+
<div class="space-y-2">
|
|
117
|
+
<CodeEditor bind:value={sqlText} class="min-h-28" />
|
|
118
|
+
<Button size="sm" variant="primary">Run SQL</Button>
|
|
119
|
+
</div>
|
|
120
|
+
{/snippet}
|
|
121
|
+
|
|
122
|
+
{#snippet cell(row, column)}
|
|
123
|
+
{#if column.id === 'status' || column.id === 'role'}
|
|
124
|
+
<Badge variant="secondary">{String(row[column.id] ?? '')}</Badge>
|
|
125
|
+
{:else}
|
|
126
|
+
{row[column.id] == null ? '' : String(row[column.id])}
|
|
127
|
+
{/if}
|
|
128
|
+
{/snippet}
|
|
129
|
+
</ResourceStudioTemplate>
|
package/dist/components/templates/ResourceStudioTemplate/ResourceStudioTemplateStory.svelte.d.ts
ADDED
|
@@ -0,0 +1,7 @@
|
|
|
1
|
+
type Example = 'crud' | 'sql' | 'mainOnly';
|
|
2
|
+
type $$ComponentProps = {
|
|
3
|
+
example?: Example;
|
|
4
|
+
};
|
|
5
|
+
declare const ResourceStudioTemplateStory: import("svelte").Component<$$ComponentProps, {}, "">;
|
|
6
|
+
type ResourceStudioTemplateStory = ReturnType<typeof ResourceStudioTemplateStory>;
|
|
7
|
+
export default ResourceStudioTemplateStory;
|
package/dist/index.d.ts
CHANGED
|
@@ -10,6 +10,7 @@ export { default as Avatar } from './components/atoms/Avatar/Avatar.svelte';
|
|
|
10
10
|
export { default as Spinner } from './components/atoms/Spinner/Spinner.svelte';
|
|
11
11
|
export { default as Toggle } from './components/atoms/Toggle/Toggle.svelte';
|
|
12
12
|
export { default as Checkbox } from './components/atoms/Checkbox/Checkbox.svelte';
|
|
13
|
+
export { default as MarqueeRect } from './components/atoms/MarqueeRect/MarqueeRect.svelte';
|
|
13
14
|
export { default as Chip } from './components/atoms/Chip/Chip.svelte';
|
|
14
15
|
export { default as Tooltip } from './components/atoms/Tooltip/Tooltip.svelte';
|
|
15
16
|
export { default as Divider } from './components/atoms/Divider/Divider.svelte';
|
|
@@ -433,6 +434,7 @@ export { default as CreditCardInput } from './components/molecules/CreditCardInp
|
|
|
433
434
|
export type { CardBrand } from './components/molecules/CreditCardInput/CreditCardInput.svelte';
|
|
434
435
|
export { default as BulkActionBar } from './components/molecules/BulkActionBar/BulkActionBar.svelte';
|
|
435
436
|
export type { BulkAction, BulkActionVariant, BulkActionBarPlacement, BulkActionBarSize, BulkActionBarTone } from './components/molecules/BulkActionBar/BulkActionBar.svelte';
|
|
437
|
+
export { default as ConditionalFormatPanel } from './components/molecules/ConditionalFormatPanel/ConditionalFormatPanel.svelte';
|
|
436
438
|
export { default as ReactionBar } from './components/molecules/ReactionBar/ReactionBar.svelte';
|
|
437
439
|
export type { ReactionItem } from './components/molecules/ReactionBar/ReactionBar.svelte';
|
|
438
440
|
export { default as AddressFields } from './components/molecules/AddressFields/AddressFields.svelte';
|
|
@@ -577,6 +579,12 @@ export type { SheetSize, SheetAccent } from './components/organisms/Sheet/Sheet.
|
|
|
577
579
|
export { SHEET_SIZE_SNAPS } from './components/organisms/Sheet/Sheet.svelte';
|
|
578
580
|
export { default as DataTable } from './components/organisms/DataTable/DataTable.svelte';
|
|
579
581
|
export type { DataTableColumn } from './components/organisms/DataTable/DataTable.svelte';
|
|
582
|
+
export { default as DataGrid } from './components/organisms/DataGrid/DataGrid.svelte';
|
|
583
|
+
export type { DataGridColumn, DataGridEditType, DataGridEditConfig, DataGridEditOption, DataGridViewMode, DataGridFilter, Breakpoint, CellRef, GridSelection, CellNote, GridMark, MarkColor, MarkPreset, ConditionalFormatRule, ConditionalFormatStyle, FormatCondition, FormatTarget, SortDir } from './components/organisms/DataGrid/DataGrid.svelte';
|
|
584
|
+
export { EMPTY_SELECTION, noteKey, markKey, selectionCount, selectionLabel, evaluateFormatRules, evaluateCondition, styleToCss, inferCellEditor, resolveCellEditor, coerceEditValue, draftFromValue, MARK_COLORS, MARK_TINT, MARK_SWATCH, markTint, markSwatch, isMarkPreset, BREAKPOINT_MIN, matchesMinBreakpoint, isColumnVisibleAtWidth, filterRows, cellText, uniqueColumnValues } from './components/organisms/DataGrid/DataGrid.svelte';
|
|
585
|
+
export { default as ResourceStudio } from './components/organisms/ResourceStudio/ResourceStudio.svelte';
|
|
586
|
+
export type { FieldType, ResourceField, ResourceCapabilities, ResourceDefinition, ResourceStudioMode, ResourceStudioLayout, ResourceStudioLabels, ResourceStudioView } from './components/organisms/ResourceStudio/ResourceStudio.svelte';
|
|
587
|
+
export { DEFAULT_CAPABILITIES, resolveCapabilities, fieldsToColumns, fieldsToSchema } from './components/organisms/ResourceStudio/ResourceStudio.svelte';
|
|
580
588
|
export { default as GanttChart } from './components/organisms/GanttChart/GanttChart.svelte';
|
|
581
589
|
export type { GanttTask } from './components/organisms/GanttChart/GanttChart.svelte';
|
|
582
590
|
export { default as ToastContainer } from './components/organisms/Toast/ToastContainer.svelte';
|
|
@@ -731,6 +739,7 @@ export { default as DashboardTemplate } from './components/templates/DashboardTe
|
|
|
731
739
|
export type { DashboardTemplateDensity } from './components/templates/DashboardTemplate/DashboardTemplate.svelte';
|
|
732
740
|
export { default as MarketingTemplate } from './components/templates/MarketingTemplate/MarketingTemplate.svelte';
|
|
733
741
|
export { default as ListingTemplate } from './components/templates/ListingTemplate/ListingTemplate.svelte';
|
|
742
|
+
export { default as ResourceStudioTemplate } from './components/templates/ResourceStudioTemplate/ResourceStudioTemplate.svelte';
|
|
734
743
|
export { default as CheckoutTemplate } from './components/templates/CheckoutTemplate/CheckoutTemplate.svelte';
|
|
735
744
|
export type { CheckoutLine, CheckoutStep, CheckoutShippingOption } from './components/templates/CheckoutTemplate/CheckoutTemplate.svelte';
|
|
736
745
|
export { default as DesktopTemplate } from './components/templates/DesktopTemplate/DesktopTemplate.svelte';
|
|
@@ -741,6 +750,8 @@ export type { VisibilityState } from './utils/pageVisibility.svelte.js';
|
|
|
741
750
|
export { network } from './utils/network.svelte.js';
|
|
742
751
|
export { DEFAULT_COLS, DEFAULT_ROW_HEIGHT, DEFAULT_GAP, GRID_DENSITY, clampItem, rectsOverlap, findCollisions, resolveCollisions, compactLayout, updateItem, addItem, removeItem, serializeLayout, parseLayout, layoutBounds, rescaleLayout, resizeItemByEdge } from './utils/layoutGrid.js';
|
|
743
752
|
export type { GridItem, LayoutGridOptions, GridDensity, GridResizeEdge } from './utils/layoutGrid.js';
|
|
753
|
+
export { attachMarqueeSelect, collectMarqueeItems, defaultMarqueeIgnore, getMarqueeModifier, hitTestIds, normalizeRect, rectsIntersect, resolveMarqueeSelection } from './utils/marqueeSelect.js';
|
|
754
|
+
export type { AttachMarqueeSelectOptions, MarqueeDragState, MarqueeItemRect, MarqueeModifier, MarqueeRect as MarqueeRectBox } from './utils/marqueeSelect.js';
|
|
744
755
|
export { encodeQR, qrToSvgPath, punchLogoHole } from './utils/qr.js';
|
|
745
756
|
export { renderMarkdown, renderInline, escapeHtml, splitTableRow, slugifyHeading } from './utils/markdown.js';
|
|
746
757
|
export { diffLines, diffWords, diffStats, toSplitRows } from './utils/diff.js';
|
package/dist/index.js
CHANGED
|
@@ -14,6 +14,7 @@ export { default as Avatar } from './components/atoms/Avatar/Avatar.svelte';
|
|
|
14
14
|
export { default as Spinner } from './components/atoms/Spinner/Spinner.svelte';
|
|
15
15
|
export { default as Toggle } from './components/atoms/Toggle/Toggle.svelte';
|
|
16
16
|
export { default as Checkbox } from './components/atoms/Checkbox/Checkbox.svelte';
|
|
17
|
+
export { default as MarqueeRect } from './components/atoms/MarqueeRect/MarqueeRect.svelte';
|
|
17
18
|
export { default as Chip } from './components/atoms/Chip/Chip.svelte';
|
|
18
19
|
export { default as Tooltip } from './components/atoms/Tooltip/Tooltip.svelte';
|
|
19
20
|
export { default as Divider } from './components/atoms/Divider/Divider.svelte';
|
|
@@ -309,6 +310,7 @@ export { default as RadarChart } from './components/molecules/RadarChart/RadarCh
|
|
|
309
310
|
export { default as InputGroup } from './components/molecules/InputGroup/InputGroup.svelte';
|
|
310
311
|
export { default as CreditCardInput } from './components/molecules/CreditCardInput/CreditCardInput.svelte';
|
|
311
312
|
export { default as BulkActionBar } from './components/molecules/BulkActionBar/BulkActionBar.svelte';
|
|
313
|
+
export { default as ConditionalFormatPanel } from './components/molecules/ConditionalFormatPanel/ConditionalFormatPanel.svelte';
|
|
312
314
|
export { default as ReactionBar } from './components/molecules/ReactionBar/ReactionBar.svelte';
|
|
313
315
|
export { default as AddressFields } from './components/molecules/AddressFields/AddressFields.svelte';
|
|
314
316
|
export { default as RichTextEditor } from './components/molecules/RichTextEditor/RichTextEditor.svelte';
|
|
@@ -397,6 +399,10 @@ export { default as Drawer } from './components/organisms/Drawer/Drawer.svelte';
|
|
|
397
399
|
export { default as Sheet } from './components/organisms/Sheet/Sheet.svelte';
|
|
398
400
|
export { SHEET_SIZE_SNAPS } from './components/organisms/Sheet/Sheet.svelte';
|
|
399
401
|
export { default as DataTable } from './components/organisms/DataTable/DataTable.svelte';
|
|
402
|
+
export { default as DataGrid } from './components/organisms/DataGrid/DataGrid.svelte';
|
|
403
|
+
export { EMPTY_SELECTION, noteKey, markKey, selectionCount, selectionLabel, evaluateFormatRules, evaluateCondition, styleToCss, inferCellEditor, resolveCellEditor, coerceEditValue, draftFromValue, MARK_COLORS, MARK_TINT, MARK_SWATCH, markTint, markSwatch, isMarkPreset, BREAKPOINT_MIN, matchesMinBreakpoint, isColumnVisibleAtWidth, filterRows, cellText, uniqueColumnValues } from './components/organisms/DataGrid/DataGrid.svelte';
|
|
404
|
+
export { default as ResourceStudio } from './components/organisms/ResourceStudio/ResourceStudio.svelte';
|
|
405
|
+
export { DEFAULT_CAPABILITIES, resolveCapabilities, fieldsToColumns, fieldsToSchema } from './components/organisms/ResourceStudio/ResourceStudio.svelte';
|
|
400
406
|
export { default as GanttChart } from './components/organisms/GanttChart/GanttChart.svelte';
|
|
401
407
|
export { default as ToastContainer } from './components/organisms/Toast/ToastContainer.svelte';
|
|
402
408
|
export { toastStore, toast } from './components/organisms/Toast/toast.svelte.js';
|
|
@@ -491,6 +497,7 @@ export { default as AuthTemplate } from './components/templates/AuthTemplate/Aut
|
|
|
491
497
|
export { default as DashboardTemplate } from './components/templates/DashboardTemplate/DashboardTemplate.svelte';
|
|
492
498
|
export { default as MarketingTemplate } from './components/templates/MarketingTemplate/MarketingTemplate.svelte';
|
|
493
499
|
export { default as ListingTemplate } from './components/templates/ListingTemplate/ListingTemplate.svelte';
|
|
500
|
+
export { default as ResourceStudioTemplate } from './components/templates/ResourceStudioTemplate/ResourceStudioTemplate.svelte';
|
|
494
501
|
export { default as CheckoutTemplate } from './components/templates/CheckoutTemplate/CheckoutTemplate.svelte';
|
|
495
502
|
export { default as DesktopTemplate } from './components/templates/DesktopTemplate/DesktopTemplate.svelte';
|
|
496
503
|
// ── Utils ────────────────────────────────────────────────────────────────────
|
|
@@ -498,6 +505,7 @@ export { themeStore } from './utils/theme.svelte.js';
|
|
|
498
505
|
export { pageVisibility } from './utils/pageVisibility.svelte.js';
|
|
499
506
|
export { network } from './utils/network.svelte.js';
|
|
500
507
|
export { DEFAULT_COLS, DEFAULT_ROW_HEIGHT, DEFAULT_GAP, GRID_DENSITY, clampItem, rectsOverlap, findCollisions, resolveCollisions, compactLayout, updateItem, addItem, removeItem, serializeLayout, parseLayout, layoutBounds, rescaleLayout, resizeItemByEdge } from './utils/layoutGrid.js';
|
|
508
|
+
export { attachMarqueeSelect, collectMarqueeItems, defaultMarqueeIgnore, getMarqueeModifier, hitTestIds, normalizeRect, rectsIntersect, resolveMarqueeSelection } from './utils/marqueeSelect.js';
|
|
501
509
|
export { encodeQR, qrToSvgPath, punchLogoHole } from './utils/qr.js';
|
|
502
510
|
export { renderMarkdown, renderInline, escapeHtml, splitTableRow, slugifyHeading } from './utils/markdown.js';
|
|
503
511
|
export { diffLines, diffWords, diffStats, toSplitRows } from './utils/diff.js';
|
|
@@ -0,0 +1,48 @@
|
|
|
1
|
+
/** Axis-aligned selection rectangle (container-local coordinates). */
|
|
2
|
+
export interface MarqueeRect {
|
|
3
|
+
x: number;
|
|
4
|
+
y: number;
|
|
5
|
+
width: number;
|
|
6
|
+
height: number;
|
|
7
|
+
}
|
|
8
|
+
/** Hit-test target with an id and box in the same coordinate space as {@link MarqueeRect}. */
|
|
9
|
+
export interface MarqueeItemRect {
|
|
10
|
+
id: string;
|
|
11
|
+
x: number;
|
|
12
|
+
y: number;
|
|
13
|
+
width: number;
|
|
14
|
+
height: number;
|
|
15
|
+
}
|
|
16
|
+
export type MarqueeModifier = 'replace' | 'add' | 'toggle';
|
|
17
|
+
export interface MarqueeDragState {
|
|
18
|
+
rect: MarqueeRect;
|
|
19
|
+
ids: string[];
|
|
20
|
+
modifier: MarqueeModifier;
|
|
21
|
+
}
|
|
22
|
+
export interface AttachMarqueeSelectOptions {
|
|
23
|
+
/** Pixels of movement before a drag becomes a marquee (keeps clicks clean). Default 4. */
|
|
24
|
+
threshold?: number;
|
|
25
|
+
/** Supply item boxes; called on each move after threshold. */
|
|
26
|
+
getItems: () => MarqueeItemRect[];
|
|
27
|
+
/** Live updates while dragging (after threshold). */
|
|
28
|
+
onDrag?: (state: MarqueeDragState) => void;
|
|
29
|
+
/** Fired on pointerup if a marquee drag occurred. */
|
|
30
|
+
onSelect: (state: MarqueeDragState) => void;
|
|
31
|
+
/** Skip starting a marquee from this event target. */
|
|
32
|
+
shouldIgnore?: (target: EventTarget | null) => boolean;
|
|
33
|
+
/** Called when the overlay rect changes (including null when idle / below threshold). */
|
|
34
|
+
onRect?: (rect: MarqueeRect | null) => void;
|
|
35
|
+
}
|
|
36
|
+
export declare function normalizeRect(x0: number, y0: number, x1: number, y1: number): MarqueeRect;
|
|
37
|
+
export declare function rectsIntersect(a: MarqueeRect, b: MarqueeRect): boolean;
|
|
38
|
+
export declare function hitTestIds(marquee: MarqueeRect, items: MarqueeItemRect[]): string[];
|
|
39
|
+
export declare function getMarqueeModifier(e: Pick<PointerEvent, 'shiftKey' | 'metaKey' | 'ctrlKey'>): MarqueeModifier;
|
|
40
|
+
export declare function resolveMarqueeSelection(hitIds: string[], previousIds: string[], modifier: MarqueeModifier): string[];
|
|
41
|
+
/** Collect `[data-marquee-id]` children in container-local (incl. scroll) coordinates. */
|
|
42
|
+
export declare function collectMarqueeItems(container: HTMLElement, selector?: string): MarqueeItemRect[];
|
|
43
|
+
export declare function defaultMarqueeIgnore(target: EventTarget | null): boolean;
|
|
44
|
+
/**
|
|
45
|
+
* Attach Windows-style rubber-band selection to a container.
|
|
46
|
+
* Returns a disposer.
|
|
47
|
+
*/
|
|
48
|
+
export declare function attachMarqueeSelect(container: HTMLElement, options: AttachMarqueeSelectOptions): () => void;
|
|
@@ -0,0 +1,189 @@
|
|
|
1
|
+
export function normalizeRect(x0, y0, x1, y1) {
|
|
2
|
+
const left = Math.min(x0, x1);
|
|
3
|
+
const top = Math.min(y0, y1);
|
|
4
|
+
return {
|
|
5
|
+
x: left,
|
|
6
|
+
y: top,
|
|
7
|
+
width: Math.abs(x1 - x0),
|
|
8
|
+
height: Math.abs(y1 - y0)
|
|
9
|
+
};
|
|
10
|
+
}
|
|
11
|
+
export function rectsIntersect(a, b) {
|
|
12
|
+
return (a.x < b.x + b.width &&
|
|
13
|
+
a.x + a.width > b.x &&
|
|
14
|
+
a.y < b.y + b.height &&
|
|
15
|
+
a.y + a.height > b.y);
|
|
16
|
+
}
|
|
17
|
+
export function hitTestIds(marquee, items) {
|
|
18
|
+
const ids = [];
|
|
19
|
+
for (const item of items) {
|
|
20
|
+
if (rectsIntersect(marquee, item))
|
|
21
|
+
ids.push(item.id);
|
|
22
|
+
}
|
|
23
|
+
return ids;
|
|
24
|
+
}
|
|
25
|
+
export function getMarqueeModifier(e) {
|
|
26
|
+
if (e.metaKey || e.ctrlKey)
|
|
27
|
+
return 'toggle';
|
|
28
|
+
if (e.shiftKey)
|
|
29
|
+
return 'add';
|
|
30
|
+
return 'replace';
|
|
31
|
+
}
|
|
32
|
+
export function resolveMarqueeSelection(hitIds, previousIds, modifier) {
|
|
33
|
+
if (modifier === 'replace')
|
|
34
|
+
return [...hitIds];
|
|
35
|
+
if (modifier === 'add')
|
|
36
|
+
return [...new Set([...previousIds, ...hitIds])];
|
|
37
|
+
const set = new Set(previousIds);
|
|
38
|
+
for (const id of hitIds) {
|
|
39
|
+
if (set.has(id))
|
|
40
|
+
set.delete(id);
|
|
41
|
+
else
|
|
42
|
+
set.add(id);
|
|
43
|
+
}
|
|
44
|
+
return [...set];
|
|
45
|
+
}
|
|
46
|
+
/** Collect `[data-marquee-id]` children in container-local (incl. scroll) coordinates. */
|
|
47
|
+
export function collectMarqueeItems(container, selector = '[data-marquee-id]') {
|
|
48
|
+
const cRect = container.getBoundingClientRect();
|
|
49
|
+
const nodes = container.querySelectorAll(selector);
|
|
50
|
+
const items = [];
|
|
51
|
+
for (const node of nodes) {
|
|
52
|
+
if (!(node instanceof HTMLElement))
|
|
53
|
+
continue;
|
|
54
|
+
const id = node.getAttribute('data-marquee-id');
|
|
55
|
+
if (!id)
|
|
56
|
+
continue;
|
|
57
|
+
const r = node.getBoundingClientRect();
|
|
58
|
+
items.push({
|
|
59
|
+
id,
|
|
60
|
+
x: r.left - cRect.left + container.scrollLeft,
|
|
61
|
+
y: r.top - cRect.top + container.scrollTop,
|
|
62
|
+
width: r.width,
|
|
63
|
+
height: r.height
|
|
64
|
+
});
|
|
65
|
+
}
|
|
66
|
+
return items;
|
|
67
|
+
}
|
|
68
|
+
export function defaultMarqueeIgnore(target) {
|
|
69
|
+
if (!(target instanceof Element))
|
|
70
|
+
return false;
|
|
71
|
+
return Boolean(target.closest('input, textarea, select, button, a, label, [data-marquee-ignore], [role="separator"], [contenteditable="true"]'));
|
|
72
|
+
}
|
|
73
|
+
function pointerInContainer(e, container) {
|
|
74
|
+
const r = container.getBoundingClientRect();
|
|
75
|
+
return {
|
|
76
|
+
x: e.clientX - r.left + container.scrollLeft,
|
|
77
|
+
y: e.clientY - r.top + container.scrollTop
|
|
78
|
+
};
|
|
79
|
+
}
|
|
80
|
+
/**
|
|
81
|
+
* Attach Windows-style rubber-band selection to a container.
|
|
82
|
+
* Returns a disposer.
|
|
83
|
+
*/
|
|
84
|
+
export function attachMarqueeSelect(container, options) {
|
|
85
|
+
const threshold = options.threshold ?? 4;
|
|
86
|
+
const shouldIgnore = options.shouldIgnore ?? defaultMarqueeIgnore;
|
|
87
|
+
let originX = 0;
|
|
88
|
+
let originY = 0;
|
|
89
|
+
let active = false;
|
|
90
|
+
let dragging = false;
|
|
91
|
+
let pointerId = null;
|
|
92
|
+
function unbindWindow() {
|
|
93
|
+
window.removeEventListener('pointermove', onPointerMove);
|
|
94
|
+
window.removeEventListener('pointerup', onPointerUp);
|
|
95
|
+
window.removeEventListener('pointercancel', onPointerUp);
|
|
96
|
+
}
|
|
97
|
+
function finish(e) {
|
|
98
|
+
if (!active)
|
|
99
|
+
return;
|
|
100
|
+
active = false;
|
|
101
|
+
const wasDragging = dragging;
|
|
102
|
+
dragging = false;
|
|
103
|
+
unbindWindow();
|
|
104
|
+
if (pointerId != null) {
|
|
105
|
+
try {
|
|
106
|
+
container.releasePointerCapture(pointerId);
|
|
107
|
+
}
|
|
108
|
+
catch {
|
|
109
|
+
/* already released */
|
|
110
|
+
}
|
|
111
|
+
pointerId = null;
|
|
112
|
+
}
|
|
113
|
+
if (!wasDragging) {
|
|
114
|
+
options.onRect?.(null);
|
|
115
|
+
return;
|
|
116
|
+
}
|
|
117
|
+
const pt = pointerInContainer(e, container);
|
|
118
|
+
const rect = normalizeRect(originX, originY, pt.x, pt.y);
|
|
119
|
+
const ids = hitTestIds(rect, options.getItems());
|
|
120
|
+
const modifier = getMarqueeModifier(e);
|
|
121
|
+
options.onSelect({ rect, ids, modifier });
|
|
122
|
+
options.onRect?.(null);
|
|
123
|
+
window.getSelection()?.removeAllRanges();
|
|
124
|
+
}
|
|
125
|
+
function onPointerDown(e) {
|
|
126
|
+
if (e.button !== 0)
|
|
127
|
+
return;
|
|
128
|
+
if (shouldIgnore(e.target))
|
|
129
|
+
return;
|
|
130
|
+
const pt = pointerInContainer(e, container);
|
|
131
|
+
originX = pt.x;
|
|
132
|
+
originY = pt.y;
|
|
133
|
+
active = true;
|
|
134
|
+
dragging = false;
|
|
135
|
+
pointerId = e.pointerId;
|
|
136
|
+
// Defer capture until drag threshold so cell/row clicks still fire.
|
|
137
|
+
window.addEventListener('pointermove', onPointerMove);
|
|
138
|
+
window.addEventListener('pointerup', onPointerUp);
|
|
139
|
+
window.addEventListener('pointercancel', onPointerUp);
|
|
140
|
+
}
|
|
141
|
+
function onPointerMove(e) {
|
|
142
|
+
if (!active)
|
|
143
|
+
return;
|
|
144
|
+
if (pointerId != null && e.pointerId !== pointerId)
|
|
145
|
+
return;
|
|
146
|
+
const pt = pointerInContainer(e, container);
|
|
147
|
+
const dx = pt.x - originX;
|
|
148
|
+
const dy = pt.y - originY;
|
|
149
|
+
if (!dragging) {
|
|
150
|
+
if (Math.hypot(dx, dy) < threshold)
|
|
151
|
+
return;
|
|
152
|
+
dragging = true;
|
|
153
|
+
if (pointerId != null) {
|
|
154
|
+
try {
|
|
155
|
+
container.setPointerCapture(pointerId);
|
|
156
|
+
}
|
|
157
|
+
catch {
|
|
158
|
+
/* ignore */
|
|
159
|
+
}
|
|
160
|
+
}
|
|
161
|
+
e.preventDefault();
|
|
162
|
+
window.getSelection()?.removeAllRanges();
|
|
163
|
+
}
|
|
164
|
+
else {
|
|
165
|
+
e.preventDefault();
|
|
166
|
+
}
|
|
167
|
+
const rect = normalizeRect(originX, originY, pt.x, pt.y);
|
|
168
|
+
options.onRect?.(rect);
|
|
169
|
+
const ids = hitTestIds(rect, options.getItems());
|
|
170
|
+
const modifier = getMarqueeModifier(e);
|
|
171
|
+
options.onDrag?.({ rect, ids, modifier });
|
|
172
|
+
}
|
|
173
|
+
function onPointerUp(e) {
|
|
174
|
+
if (pointerId != null && e.pointerId !== pointerId)
|
|
175
|
+
return;
|
|
176
|
+
finish(e);
|
|
177
|
+
}
|
|
178
|
+
function onLostCapture(e) {
|
|
179
|
+
if (e.pointerId === pointerId)
|
|
180
|
+
finish(e);
|
|
181
|
+
}
|
|
182
|
+
container.addEventListener('pointerdown', onPointerDown);
|
|
183
|
+
container.addEventListener('lostpointercapture', onLostCapture);
|
|
184
|
+
return () => {
|
|
185
|
+
unbindWindow();
|
|
186
|
+
container.removeEventListener('pointerdown', onPointerDown);
|
|
187
|
+
container.removeEventListener('lostpointercapture', onLostCapture);
|
|
188
|
+
};
|
|
189
|
+
}
|