@svadmin/ui 0.72.0 → 0.73.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/README.md +40 -25
- package/THIRD_PARTY_NOTICES.md +52 -0
- package/dist/app.css +7694 -5117
- package/dist/app.theme.css +7645 -5119
- package/dist/class-properties.generated.d.ts +1 -0
- package/dist/class-properties.generated.js +2 -0
- package/dist/classnames.d.ts +8 -0
- package/dist/classnames.js +26 -0
- package/dist/components/AutoForm.svelte +20 -6
- package/dist/components/AutoForm.svelte.d.ts +2 -0
- package/dist/components/AutoTable.svelte +249 -9
- package/dist/components/AutoTable.svelte.d.ts +5 -0
- package/dist/components/BoundRecordDetailDrawer.svelte +8 -2
- package/dist/components/BoundRecordDetailDrawer.svelte.d.ts +2 -0
- package/dist/components/ComboboxField.svelte +31 -9
- package/dist/components/ComboboxField.svelte.d.ts +3 -2
- package/dist/components/CreatePage.svelte +4 -0
- package/dist/components/CreatePage.svelte.d.ts +2 -0
- package/dist/components/DateRangeInput.svelte +75 -0
- package/dist/components/DateRangeInput.svelte.d.ts +25 -0
- package/dist/components/DateTimeInput.svelte +65 -0
- package/dist/components/DateTimeInput.svelte.d.ts +19 -0
- package/dist/components/DevTools.svelte +2 -2
- package/dist/components/EditPage.svelte +4 -0
- package/dist/components/EditPage.svelte.d.ts +2 -0
- package/dist/components/FieldRenderer.svelte +90 -18
- package/dist/components/FileUpload.svelte +250 -0
- package/dist/components/FileUpload.svelte.d.ts +32 -0
- package/dist/components/FilterBuilder.svelte +236 -279
- package/dist/components/FilterBuilder.svelte.d.ts +3 -0
- package/dist/components/ImportWizard.svelte +181 -94
- package/dist/components/JsonSchemaForm.svelte +255 -99
- package/dist/components/JsonSchemaForm.svelte.d.ts +12 -1
- package/dist/components/Layout.svelte +1 -2
- package/dist/components/LazyTaskQueueDrawer.svelte.d.ts +1 -1
- package/dist/components/ListPage.svelte +4 -0
- package/dist/components/ListPage.svelte.d.ts +2 -0
- package/dist/components/LoginPage.svelte +1 -1
- package/dist/components/MoneyInput.svelte +25 -0
- package/dist/components/MoneyInput.svelte.d.ts +20 -0
- package/dist/components/NumberInput.svelte +25 -0
- package/dist/components/NumberInput.svelte.d.ts +19 -0
- package/dist/components/NumericInput.svelte +110 -0
- package/dist/components/NumericInput.svelte.d.ts +23 -0
- package/dist/components/PercentInput.svelte +25 -0
- package/dist/components/PercentInput.svelte.d.ts +20 -0
- package/dist/components/QuickEditDrawer.svelte +4 -1
- package/dist/components/QuickEditDrawer.svelte.d.ts +2 -0
- package/dist/components/RecordDetailDrawer.svelte +4 -2
- package/dist/components/RecordDetailDrawer.svelte.d.ts +2 -0
- package/dist/components/ResourceOperationsPage.svelte +25 -19
- package/dist/components/ResourceOperationsPage.svelte.d.ts +5 -1
- package/dist/components/ShowInferencer.svelte +4 -2
- package/dist/components/ShowInferencer.svelte.d.ts +2 -0
- package/dist/components/ShowPage.svelte +7 -3
- package/dist/components/ShowPage.svelte.d.ts +2 -0
- package/dist/components/Sidebar.svelte +5 -5
- package/dist/components/SpreadsheetView.svelte +81 -286
- package/dist/components/StepsForm.svelte +5 -5
- package/dist/components/SvarAutoTable.svelte +39 -0
- package/dist/components/SvarAutoTable.svelte.d.ts +13 -0
- package/dist/components/SvarDataGrid.svelte +362 -0
- package/dist/components/SvarDataGrid.svelte.d.ts +57 -0
- package/dist/components/SvarGridCell.svelte +10 -0
- package/dist/components/SvarGridCell.svelte.d.ts +7 -0
- package/dist/components/SvarResourceRead.svelte +50 -0
- package/dist/components/SvarResourceRead.svelte.d.ts +23 -0
- package/dist/components/SvarResourceTable.svelte +63 -0
- package/dist/components/SvarResourceTable.svelte.d.ts +42 -0
- package/dist/components/SvarResourceTableView.svelte +364 -0
- package/dist/components/SvarResourceTableView.svelte.d.ts +4 -0
- package/dist/components/TaskQueueDrawer.svelte +72 -16
- package/dist/components/TreeSelect.svelte +208 -28
- package/dist/components/TreeSelect.svelte.d.ts +3 -1
- package/dist/components/auto-table-grid.d.ts +26 -0
- package/dist/components/auto-table-grid.js +1 -0
- package/dist/components/content/ContentPageHeader.svelte +12 -9
- package/dist/components/content/ContentPageShell.svelte +6 -9
- package/dist/components/content/FileBrowser.svelte +35 -0
- package/dist/components/content/FileBrowser.svelte.d.ts +14 -0
- package/dist/components/content/MetricBlock.svelte +10 -13
- package/dist/components/content/NetworkTable.svelte +3 -3
- package/dist/components/content/NetworkTable.svelte.d.ts +1 -0
- package/dist/components/content/PageToolbar.svelte +6 -10
- package/dist/components/content/SectionHeader.svelte +8 -13
- package/dist/components/content/SettingsFieldRow.svelte +9 -23
- package/dist/components/content/SettingsGroup.svelte +11 -27
- package/dist/components/content/StatusBadge.svelte +3 -8
- package/dist/components/content/WorkspaceLayout.svelte +8 -12
- package/dist/components/enterprise/filter-tree.d.ts +48 -0
- package/dist/components/enterprise/filter-tree.js +224 -0
- package/dist/components/enterprise/json-schema-form.d.ts +39 -0
- package/dist/components/enterprise/json-schema-form.js +195 -0
- package/dist/components/enterprise/recursive-schema-form.d.ts +30 -0
- package/dist/components/enterprise/recursive-schema-form.js +196 -0
- package/dist/components/enterprise/spreadsheet-formula.d.ts +12 -0
- package/dist/components/enterprise/spreadsheet-formula.js +245 -0
- package/dist/components/fieldComponentMap.js +5 -0
- package/dist/components/fields/DateField.svelte +4 -3
- package/dist/components/fields/date-field-value.d.ts +2 -0
- package/dist/components/fields/date-field-value.js +13 -0
- package/dist/components/json-schema-form-state.d.ts +37 -0
- package/dist/components/json-schema-form-state.js +168 -0
- package/dist/components/record-detail.svelte.d.ts +3 -0
- package/dist/components/record-detail.svelte.js +10 -4
- package/dist/components/svar-grid-cells.d.ts +14 -0
- package/dist/components/svar-grid-cells.js +2 -0
- package/dist/components/svar-grid-contract.d.ts +80 -0
- package/dist/components/svar-grid-contract.js +159 -0
- package/dist/components/svar-grid-interactions.d.ts +54 -0
- package/dist/components/svar-grid-interactions.js +174 -0
- package/dist/components/svar-grid-loading.d.ts +40 -0
- package/dist/components/svar-grid-loading.js +180 -0
- package/dist/components/svar-grid-operations.d.ts +37 -0
- package/dist/components/svar-grid-operations.js +186 -0
- package/dist/components/svar-grid-panes.d.ts +34 -0
- package/dist/components/svar-grid-panes.js +66 -0
- package/dist/components/svar-grid-resource-loading.d.ts +18 -0
- package/dist/components/svar-grid-resource-loading.js +68 -0
- package/dist/components/svar-grid-resource-session.svelte.d.ts +29 -0
- package/dist/components/svar-grid-resource-session.svelte.js +61 -0
- package/dist/components/ui/badge/badge-variants.js +3 -1
- package/dist/components/ui/button/button-variants.js +5 -2
- package/dist/components/ui/input/input.svelte +1 -4
- package/dist/components/ui/textarea/textarea.svelte +2 -1
- package/dist/components.css +3079 -0
- package/dist/design-contract.d.ts +13 -0
- package/dist/design-contract.js +11 -0
- package/dist/design-system.d.ts +15 -0
- package/dist/design-system.js +7 -0
- package/dist/index.d.ts +14 -0
- package/dist/index.js +9 -0
- package/dist/page-chrome.css +12 -49
- package/dist/recipes.d.ts +4 -0
- package/dist/recipes.js +4 -0
- package/dist/rendering/index.d.ts +87 -0
- package/dist/rendering/index.js +117 -0
- package/dist/styled-system/css/conditions.js +36 -0
- package/dist/styled-system/css/css.d.ts +22 -0
- package/dist/styled-system/css/css.js +45 -0
- package/dist/styled-system/css/cva.d.ts +6 -0
- package/dist/styled-system/css/cva.js +87 -0
- package/dist/styled-system/css/cx.d.ts +5 -0
- package/dist/styled-system/css/cx.js +15 -0
- package/dist/styled-system/css/index.d.ts +5 -0
- package/dist/styled-system/css/index.js +4 -0
- package/dist/styled-system/css/sva.d.ts +4 -0
- package/dist/styled-system/css/sva.js +46 -0
- package/dist/styled-system/helpers.js +316 -0
- package/dist/styled-system/patterns/aspect-ratio.d.ts +20 -0
- package/dist/styled-system/patterns/aspect-ratio.js +38 -0
- package/dist/styled-system/patterns/bleed.d.ts +21 -0
- package/dist/styled-system/patterns/bleed.js +24 -0
- package/dist/styled-system/patterns/box.d.ts +20 -0
- package/dist/styled-system/patterns/box.js +15 -0
- package/dist/styled-system/patterns/center.d.ts +20 -0
- package/dist/styled-system/patterns/center.js +21 -0
- package/dist/styled-system/patterns/circle.d.ts +20 -0
- package/dist/styled-system/patterns/circle.js +25 -0
- package/dist/styled-system/patterns/container.d.ts +20 -0
- package/dist/styled-system/patterns/container.js +21 -0
- package/dist/styled-system/patterns/cq.d.ts +21 -0
- package/dist/styled-system/patterns/cq.js +21 -0
- package/dist/styled-system/patterns/divider.d.ts +22 -0
- package/dist/styled-system/patterns/divider.js +25 -0
- package/dist/styled-system/patterns/flex.d.ts +26 -0
- package/dist/styled-system/patterns/flex.js +26 -0
- package/dist/styled-system/patterns/float.d.ts +23 -0
- package/dist/styled-system/patterns/float.js +52 -0
- package/dist/styled-system/patterns/grid-item.d.ts +25 -0
- package/dist/styled-system/patterns/grid-item.js +25 -0
- package/dist/styled-system/patterns/grid.d.ts +24 -0
- package/dist/styled-system/patterns/grid.js +27 -0
- package/dist/styled-system/patterns/hstack.d.ts +21 -0
- package/dist/styled-system/patterns/hstack.js +24 -0
- package/dist/styled-system/patterns/index.d.ts +21 -0
- package/dist/styled-system/patterns/index.js +20 -0
- package/dist/styled-system/patterns/link-overlay.d.ts +20 -0
- package/dist/styled-system/patterns/link-overlay.js +24 -0
- package/dist/styled-system/patterns/spacer.d.ts +20 -0
- package/dist/styled-system/patterns/spacer.js +25 -0
- package/dist/styled-system/patterns/square.d.ts +20 -0
- package/dist/styled-system/patterns/square.js +24 -0
- package/dist/styled-system/patterns/stack.d.ts +23 -0
- package/dist/styled-system/patterns/stack.js +24 -0
- package/dist/styled-system/patterns/visually-hidden.d.ts +20 -0
- package/dist/styled-system/patterns/visually-hidden.js +18 -0
- package/dist/styled-system/patterns/vstack.d.ts +21 -0
- package/dist/styled-system/patterns/vstack.js +24 -0
- package/dist/styled-system/patterns/wrap.d.ts +24 -0
- package/dist/styled-system/patterns/wrap.js +25 -0
- package/dist/styled-system/recipes/content-header.d.ts +31 -0
- package/dist/styled-system/recipes/content-header.js +65 -0
- package/dist/styled-system/recipes/content-page.d.ts +34 -0
- package/dist/styled-system/recipes/content-page.js +43 -0
- package/dist/styled-system/recipes/create-recipe.js +82 -0
- package/dist/styled-system/recipes/index.d.ts +17 -0
- package/dist/styled-system/recipes/index.js +16 -0
- package/dist/styled-system/recipes/metric-block.d.ts +34 -0
- package/dist/styled-system/recipes/metric-block.js +76 -0
- package/dist/styled-system/recipes/product-list.d.ts +31 -0
- package/dist/styled-system/recipes/product-list.js +73 -0
- package/dist/styled-system/recipes/product-section.d.ts +31 -0
- package/dist/styled-system/recipes/product-section.js +49 -0
- package/dist/styled-system/recipes/product-settings-row.d.ts +34 -0
- package/dist/styled-system/recipes/product-settings-row.js +58 -0
- package/dist/styled-system/recipes/product-settings.d.ts +31 -0
- package/dist/styled-system/recipes/product-settings.js +57 -0
- package/dist/styled-system/recipes/product-status.d.ts +34 -0
- package/dist/styled-system/recipes/product-status.js +45 -0
- package/dist/styled-system/recipes/product-toolbar.d.ts +31 -0
- package/dist/styled-system/recipes/product-toolbar.js +41 -0
- package/dist/styled-system/recipes/product-workspace.d.ts +34 -0
- package/dist/styled-system/recipes/product-workspace.js +58 -0
- package/dist/styled-system/recipes/surface-metric.d.ts +38 -0
- package/dist/styled-system/recipes/surface-metric.js +63 -0
- package/dist/styled-system/recipes/surface-table.d.ts +34 -0
- package/dist/styled-system/recipes/surface-table.js +62 -0
- package/dist/styled-system/recipes/ui-badge.d.ts +31 -0
- package/dist/styled-system/recipes/ui-badge.js +38 -0
- package/dist/styled-system/recipes/ui-button.d.ts +32 -0
- package/dist/styled-system/recipes/ui-button.js +43 -0
- package/dist/styled-system/recipes/ui-input.d.ts +31 -0
- package/dist/styled-system/recipes/ui-input.js +49 -0
- package/dist/styled-system/recipes/ui-textarea.d.ts +31 -0
- package/dist/styled-system/recipes/ui-textarea.js +24 -0
- package/dist/styled-system/styles.css +1257 -0
- package/dist/styled-system/tokens/index.d.ts +9 -0
- package/dist/styled-system/tokens/index.js +268 -0
- package/dist/styled-system/tokens/tokens.d.ts +36 -0
- package/dist/styled-system/types/composition.d.ts +227 -0
- package/dist/styled-system/types/conditions.d.ts +236 -0
- package/dist/styled-system/types/csstype.d.ts +22570 -0
- package/dist/styled-system/types/index.d.ts +6 -0
- package/dist/styled-system/types/parts.d.ts +8 -0
- package/dist/styled-system/types/pattern.d.ts +78 -0
- package/dist/styled-system/types/prop-type.d.ts +223 -0
- package/dist/styled-system/types/recipe.d.ts +181 -0
- package/dist/styled-system/types/selectors.d.ts +59 -0
- package/dist/styled-system/types/static-css.d.ts +56 -0
- package/dist/styled-system/types/style-props.d.ts +8088 -0
- package/dist/styled-system/types/system-types.d.ts +151 -0
- package/dist/styles/aliases.css +49 -0
- package/dist/styles/compatibility.epilogue.css +384 -0
- package/dist/styles/compatibility.prelude.css +5513 -0
- package/dist/styles/conditional-states.css +28 -0
- package/dist/styles/conditional-utilities.css +22 -0
- package/dist/styles/recipes.css +1262 -0
- package/dist/utils.d.ts +1 -1
- package/dist/utils.js +1 -1
- package/package.json +31 -13
- package/styles-compatibility.json +12 -0
|
@@ -309,10 +309,10 @@
|
|
|
309
309
|
aria-label="Sidebar navigation"
|
|
310
310
|
class="svadmin-u-7bc555991dba svadmin-u-5f89f14a26db svadmin-u-c78facc7a0a6 svadmin-u-0f2fff0ae96e svadmin-u-60fbb7713999 svadmin-u-8dddea0773ed svadmin-u-5ceb636bd9f3 svadmin-u-6ee2d41e2d2d svadmin-u-0fe7d7d814d0 svadmin-u-7890552ecd63"
|
|
311
311
|
style="background-color: var(--sidebar);"
|
|
312
|
-
class:
|
|
313
|
-
class:
|
|
312
|
+
class:svadmin-sidebar--expanded={!collapsed}
|
|
313
|
+
class:svadmin-sidebar--collapsed={collapsed}
|
|
314
314
|
>
|
|
315
|
-
<div class="svadmin-u-60fbb7713999 svadmin-u-07017cde3e97 svadmin-u-3960ffc248d9 svadmin-u-012fbd121f37" class:
|
|
315
|
+
<div class="svadmin-u-60fbb7713999 svadmin-u-07017cde3e97 svadmin-u-3960ffc248d9 svadmin-u-012fbd121f37" class:svadmin-u-d139dd09e38d={!collapsed} class:svadmin-u-86843cf1e227={collapsed}>
|
|
316
316
|
{#if !collapsed}
|
|
317
317
|
<a href={formatSidebarLink('/')} class="group svadmin-u-60fbb7713999 svadmin-u-3960ffc248d9 svadmin-u-7e9a2a250cc3" onclick={(e) => { e.preventDefault(); adminContext.navigate('/'); }}>
|
|
318
318
|
<SvadminLogo />
|
|
@@ -331,7 +331,7 @@
|
|
|
331
331
|
</div>
|
|
332
332
|
|
|
333
333
|
<ScrollArea class="svadmin-u-36e579c0b41c sidebar-scroll">
|
|
334
|
-
<nav aria-label="Main menu" class="svadmin-u-9fcd8a13827e" class:
|
|
334
|
+
<nav aria-label="Main menu" class="svadmin-u-9fcd8a13827e" class:svadmin-u-7597e11b4d4b={!collapsed} class:svadmin-u-d5eab218aa34={collapsed}>
|
|
335
335
|
{#if menu && menu.length > 0}
|
|
336
336
|
<div class="svadmin-u-a26339f4b89e">
|
|
337
337
|
{#each customMenuItems as item (item.name)}
|
|
@@ -511,7 +511,7 @@
|
|
|
511
511
|
<Tooltip.Root>
|
|
512
512
|
<Tooltip.Trigger>
|
|
513
513
|
{#snippet child({ props }: { props: Record<string, unknown> })}
|
|
514
|
-
<Button {...props} variant="ghost" size="icon" onclick={onToggle} class="svadmin-u-ed8a5df7b2fb svadmin-u-2bbcfc3b5179 svadmin-u-421ac2be5045 svadmin-u-68d55a736ff4 svadmin-u-55d1f8b9d318 svadmin-u-646e10356266">
|
|
514
|
+
<Button {...props} aria-label={i18n.t('common.toggleSidebar')} variant="ghost" size="icon" onclick={onToggle} class="svadmin-u-ed8a5df7b2fb svadmin-u-2bbcfc3b5179 svadmin-u-421ac2be5045 svadmin-u-68d55a736ff4 svadmin-u-55d1f8b9d318 svadmin-u-646e10356266">
|
|
515
515
|
<ChevronRight class="svadmin-u-7fc7f732bf7e svadmin-u-bf600f8e029c" />
|
|
516
516
|
</Button>
|
|
517
517
|
{/snippet}
|
|
@@ -2,15 +2,15 @@
|
|
|
2
2
|
import { Button } from './ui/button/index.js';
|
|
3
3
|
import { Plus, Download, FileSpreadsheet } from '@lucide/svelte';
|
|
4
4
|
import { cn } from '../utils.js';
|
|
5
|
+
import { evaluateFormula, safeSpreadsheetCsvText } from './enterprise/spreadsheet-formula.js';
|
|
5
6
|
|
|
6
7
|
export interface SheetData {
|
|
7
8
|
id: string;
|
|
8
9
|
name: string;
|
|
9
10
|
rows: number;
|
|
10
11
|
cols: number;
|
|
11
|
-
cells: Record<string, string>;
|
|
12
|
+
cells: Record<string, string>;
|
|
12
13
|
}
|
|
13
|
-
|
|
14
14
|
interface Props {
|
|
15
15
|
sheets?: SheetData[];
|
|
16
16
|
activeSheetId?: string;
|
|
@@ -19,308 +19,125 @@
|
|
|
19
19
|
onexport?: (csv: string) => void;
|
|
20
20
|
class?: string;
|
|
21
21
|
}
|
|
22
|
-
|
|
23
22
|
let {
|
|
24
|
-
sheets = $bindable([
|
|
25
|
-
|
|
26
|
-
|
|
27
|
-
|
|
28
|
-
|
|
29
|
-
|
|
30
|
-
cells: {
|
|
31
|
-
A1: 'Category',
|
|
32
|
-
B1: 'Q1',
|
|
33
|
-
C1: 'Q2',
|
|
34
|
-
D1: 'Q3',
|
|
35
|
-
E1: 'Q4',
|
|
36
|
-
F1: 'Total',
|
|
37
|
-
A2: 'Revenue',
|
|
38
|
-
B2: '12000',
|
|
39
|
-
C2: '15000',
|
|
40
|
-
D2: '18000',
|
|
41
|
-
E2: '21000',
|
|
42
|
-
F2: '=SUM(B2:E2)',
|
|
43
|
-
A3: 'Cost',
|
|
44
|
-
B3: '4000',
|
|
45
|
-
C3: '5000',
|
|
46
|
-
D3: '6000',
|
|
47
|
-
E3: '7000',
|
|
48
|
-
F3: '=SUM(B3:E3)',
|
|
49
|
-
},
|
|
50
|
-
},
|
|
51
|
-
]),
|
|
52
|
-
activeSheetId = $bindable('sheet1'),
|
|
53
|
-
readonly = false,
|
|
54
|
-
onchange,
|
|
55
|
-
onexport,
|
|
56
|
-
class: className = '',
|
|
23
|
+
sheets = $bindable([{ id: 'sheet1', name: 'Financial Summary', rows: 8, cols: 6, cells: {
|
|
24
|
+
A1: 'Category', B1: 'Q1', C1: 'Q2', D1: 'Q3', E1: 'Q4', F1: 'Total',
|
|
25
|
+
A2: 'Revenue', B2: '12000', C2: '15000', D2: '18000', E2: '21000', F2: '=SUM(B2:E2)',
|
|
26
|
+
A3: 'Cost', B3: '4000', C3: '5000', D3: '6000', E3: '7000', F3: '=SUM(B3:E3)',
|
|
27
|
+
} }]),
|
|
28
|
+
activeSheetId = $bindable('sheet1'), readonly = false, onchange, onexport, class: className = '',
|
|
57
29
|
}: Props = $props();
|
|
58
|
-
|
|
59
|
-
let
|
|
60
|
-
|
|
61
|
-
|
|
62
|
-
const currentSheet = $derived(
|
|
63
|
-
sheets.find((s) => s.id === activeSheetId) ?? sheets[0]
|
|
64
|
-
);
|
|
30
|
+
let selectedCell = $state('A1');
|
|
31
|
+
let nextSheetId = 0;
|
|
32
|
+
const currentSheet = $derived(sheets.find((sheet) => sheet.id === activeSheetId) ?? sheets[0]);
|
|
33
|
+
const formulaInput = $derived(currentSheet?.cells[selectedCell] ?? '');
|
|
65
34
|
|
|
66
35
|
function getColName(index: number): string {
|
|
67
|
-
let result = '';
|
|
68
|
-
|
|
69
|
-
while (i >= 0) {
|
|
70
|
-
result = String.fromCharCode((i % 26) + 65) + result;
|
|
71
|
-
i = Math.floor(i / 26) - 1;
|
|
72
|
-
}
|
|
36
|
+
let result = '', current = index;
|
|
37
|
+
while (current >= 0) { result = String.fromCharCode(current % 26 + 65) + result; current = Math.floor(current / 26) - 1; }
|
|
73
38
|
return result;
|
|
74
39
|
}
|
|
75
|
-
|
|
76
|
-
function colNameToIndex(col: string): number {
|
|
77
|
-
let idx = 0;
|
|
78
|
-
for (let i = 0; i < col.length; i++) {
|
|
79
|
-
idx = idx * 26 + (col.charCodeAt(i) - 64);
|
|
80
|
-
}
|
|
81
|
-
return idx - 1;
|
|
82
|
-
}
|
|
83
|
-
|
|
84
|
-
function parseCellKey(key: string): { col: string; row: number } | null {
|
|
85
|
-
const match = key.match(/^([A-Z]+)(\d+)$/);
|
|
86
|
-
if (!match || !match[1] || !match[2]) return null;
|
|
87
|
-
return { col: match[1], row: parseInt(match[2], 10) };
|
|
88
|
-
}
|
|
89
|
-
|
|
90
|
-
function evaluateFormula(formula: string, cells: Record<string, string>): number | string {
|
|
91
|
-
const sumMatch = formula.match(/^=SUM\(([A-Z]+\d+):([A-Z]+\d+)\)$/i);
|
|
92
|
-
const avgMatch = formula.match(/^=AVG\(([A-Z]+\d+):([A-Z]+\d+)\)$/i);
|
|
93
|
-
const countMatch = formula.match(/^=COUNT\(([A-Z]+\d+):([A-Z]+\d+)\)$/i);
|
|
94
|
-
|
|
95
|
-
const match = sumMatch || avgMatch || countMatch;
|
|
96
|
-
if (match && match[1] && match[2]) {
|
|
97
|
-
const start = parseCellKey(match[1].toUpperCase());
|
|
98
|
-
const end = parseCellKey(match[2].toUpperCase());
|
|
99
|
-
if (!start || !end) return '#ERROR!';
|
|
100
|
-
|
|
101
|
-
const startCol = colNameToIndex(start.col);
|
|
102
|
-
const endCol = colNameToIndex(end.col);
|
|
103
|
-
const minCol = Math.min(startCol, endCol);
|
|
104
|
-
const maxCol = Math.max(startCol, endCol);
|
|
105
|
-
const minRow = Math.min(start.row, end.row);
|
|
106
|
-
const maxRow = Math.max(start.row, end.row);
|
|
107
|
-
|
|
108
|
-
const numbers: number[] = [];
|
|
109
|
-
for (let c = minCol; c <= maxCol; c++) {
|
|
110
|
-
for (let r = minRow; r <= maxRow; r++) {
|
|
111
|
-
const k = `${getColName(c)}${r}`;
|
|
112
|
-
const raw = cells[k] ?? '';
|
|
113
|
-
const val = raw.startsWith('=') ? evaluateFormula(raw, cells) : Number(raw);
|
|
114
|
-
if (typeof val === 'number' && !isNaN(val)) {
|
|
115
|
-
numbers.push(val);
|
|
116
|
-
}
|
|
117
|
-
}
|
|
118
|
-
}
|
|
119
|
-
|
|
120
|
-
if (sumMatch) return numbers.reduce((a, b) => a + b, 0);
|
|
121
|
-
if (avgMatch) return numbers.length ? numbers.reduce((a, b) => a + b, 0) / numbers.length : 0;
|
|
122
|
-
if (countMatch) return numbers.length;
|
|
123
|
-
}
|
|
124
|
-
|
|
125
|
-
// Direct arithmetic
|
|
126
|
-
if (formula.startsWith('=')) {
|
|
127
|
-
try {
|
|
128
|
-
const expr = formula.slice(1).replace(/([A-Z]+\d+)/g, (k) => {
|
|
129
|
-
const val = cells[k.toUpperCase()] ?? '0';
|
|
130
|
-
return String(Number(val) || 0);
|
|
131
|
-
});
|
|
132
|
-
const sanitized = expr.replace(/[^0-9+\-*/(). ]/g, '');
|
|
133
|
-
const fn = new Function(`return (${sanitized || 0})`);
|
|
134
|
-
return Number(fn());
|
|
135
|
-
} catch {
|
|
136
|
-
return '#VALUE!';
|
|
137
|
-
}
|
|
138
|
-
}
|
|
139
|
-
|
|
140
|
-
return formula;
|
|
141
|
-
}
|
|
142
|
-
|
|
143
40
|
function getRenderedValue(key: string): string {
|
|
144
41
|
if (!currentSheet) return '';
|
|
145
|
-
const
|
|
146
|
-
|
|
147
|
-
const computed = evaluateFormula(raw, currentSheet.cells);
|
|
148
|
-
return typeof computed === 'number'
|
|
149
|
-
? computed.toLocaleString(undefined, { maximumFractionDigits: 2 })
|
|
150
|
-
: String(computed);
|
|
151
|
-
}
|
|
152
|
-
return raw;
|
|
42
|
+
const computed = evaluateFormula(currentSheet.cells[key] ?? '', currentSheet.cells);
|
|
43
|
+
return typeof computed === 'number' ? computed.toLocaleString(undefined, { maximumFractionDigits: 2 }) : computed;
|
|
153
44
|
}
|
|
154
|
-
|
|
155
|
-
function
|
|
156
|
-
selectedCell = key;
|
|
157
|
-
if (currentSheet) {
|
|
158
|
-
formulaInput = currentSheet.cells[key] ?? '';
|
|
159
|
-
}
|
|
160
|
-
}
|
|
161
|
-
|
|
162
|
-
function updateCellValue(key: string, val: string) {
|
|
45
|
+
function selectCell(key: string): void { selectedCell = key; }
|
|
46
|
+
function updateCellValue(key: string, next: string): void {
|
|
163
47
|
if (readonly || !currentSheet) return;
|
|
164
|
-
const
|
|
165
|
-
|
|
166
|
-
return {
|
|
167
|
-
...s,
|
|
168
|
-
cells: {
|
|
169
|
-
...s.cells,
|
|
170
|
-
[key]: val,
|
|
171
|
-
},
|
|
172
|
-
};
|
|
173
|
-
}
|
|
174
|
-
return s;
|
|
175
|
-
});
|
|
176
|
-
sheets = nextSheets;
|
|
48
|
+
const id = currentSheet.id;
|
|
49
|
+
sheets = sheets.map((sheet) => sheet.id === id ? { ...sheet, cells: { ...sheet.cells, [key]: next } } : sheet);
|
|
177
50
|
onchange?.(sheets);
|
|
178
51
|
}
|
|
179
|
-
|
|
180
|
-
|
|
181
|
-
|
|
182
|
-
|
|
183
|
-
}
|
|
184
|
-
|
|
185
|
-
function addRow() {
|
|
186
|
-
if (!currentSheet) return;
|
|
187
|
-
const next = sheets.map((s) => (s.id === currentSheet.id ? { ...s, rows: s.rows + 1 } : s));
|
|
188
|
-
sheets = next;
|
|
52
|
+
function addRow(): void {
|
|
53
|
+
if (readonly || !currentSheet) return;
|
|
54
|
+
const id = currentSheet.id;
|
|
55
|
+
sheets = sheets.map((sheet) => sheet.id === id ? { ...sheet, rows: sheet.rows + 1 } : sheet);
|
|
189
56
|
onchange?.(sheets);
|
|
190
57
|
}
|
|
191
|
-
|
|
192
|
-
|
|
193
|
-
|
|
194
|
-
|
|
195
|
-
sheets = next;
|
|
58
|
+
function addCol(): void {
|
|
59
|
+
if (readonly || !currentSheet) return;
|
|
60
|
+
const id = currentSheet.id;
|
|
61
|
+
sheets = sheets.map((sheet) => sheet.id === id ? { ...sheet, cols: sheet.cols + 1 } : sheet);
|
|
196
62
|
onchange?.(sheets);
|
|
197
63
|
}
|
|
198
|
-
|
|
199
|
-
function exportCsv() {
|
|
64
|
+
function exportCsv(): void {
|
|
200
65
|
if (!currentSheet) return;
|
|
66
|
+
const sheet = currentSheet;
|
|
201
67
|
const lines: string[] = [];
|
|
202
|
-
for (let
|
|
203
|
-
const
|
|
204
|
-
for (let
|
|
205
|
-
const
|
|
206
|
-
const
|
|
207
|
-
|
|
68
|
+
for (let row = 1; row <= sheet.rows; row++) {
|
|
69
|
+
const values: string[] = [];
|
|
70
|
+
for (let column = 0; column < sheet.cols; column++) {
|
|
71
|
+
const key = `${getColName(column)}${row}`;
|
|
72
|
+
const computed = evaluateFormula(sheet.cells[key] ?? '', sheet.cells);
|
|
73
|
+
// 数值导出保持机器可读精度;文本危险前缀与 CSV 引号分别处理。
|
|
74
|
+
const numericText = typeof computed === 'string' && /^[+-]?(?:\d+(?:\.\d*)?|\.\d+)(?:e[+-]?\d+)?$/i.test(computed.trim()) && Number.isFinite(Number(computed));
|
|
75
|
+
const text = typeof computed === 'number' || numericText ? String(computed) : safeSpreadsheetCsvText(computed);
|
|
76
|
+
values.push(`"${text.replaceAll('"', '""')}"`);
|
|
208
77
|
}
|
|
209
|
-
lines.push(
|
|
210
|
-
}
|
|
211
|
-
const csvContent = lines.join('\n');
|
|
212
|
-
if (onexport) {
|
|
213
|
-
onexport(csvContent);
|
|
214
|
-
} else {
|
|
215
|
-
const blob = new Blob([csvContent], { type: 'text/csv;charset=utf-8;' });
|
|
216
|
-
const a = document.createElement('a');
|
|
217
|
-
a.href = URL.createObjectURL(blob);
|
|
218
|
-
a.download = `${currentSheet.name}_${Date.now()}.csv`;
|
|
219
|
-
a.click();
|
|
78
|
+
lines.push(values.join(','));
|
|
220
79
|
}
|
|
80
|
+
const csv = lines.join('\n');
|
|
81
|
+
if (onexport) { onexport(csv); return; }
|
|
82
|
+
if (typeof document === 'undefined') return;
|
|
83
|
+
const url = URL.createObjectURL(new Blob([csv], { type: 'text/csv;charset=utf-8;' }));
|
|
84
|
+
try {
|
|
85
|
+
const anchor = document.createElement('a');
|
|
86
|
+
anchor.href = url;
|
|
87
|
+
anchor.download = `${sheet.name}_${Date.now()}.csv`;
|
|
88
|
+
anchor.click();
|
|
89
|
+
} finally { setTimeout(() => URL.revokeObjectURL(url), 0); }
|
|
221
90
|
}
|
|
222
|
-
|
|
223
|
-
|
|
224
|
-
const id = `sheet_${Date.now()}`;
|
|
225
|
-
|
|
226
|
-
id,
|
|
227
|
-
name: `Sheet ${sheets.length + 1}`,
|
|
228
|
-
rows: 6,
|
|
229
|
-
cols: 5,
|
|
230
|
-
cells: {},
|
|
231
|
-
};
|
|
232
|
-
sheets = [...sheets, newSheet];
|
|
91
|
+
function addSheet(): void {
|
|
92
|
+
if (readonly) return;
|
|
93
|
+
const id = `sheet_${Date.now()}_${++nextSheetId}`;
|
|
94
|
+
sheets = [...sheets, { id, name: `Sheet ${sheets.length + 1}`, rows: 6, cols: 5, cells: {} }];
|
|
233
95
|
activeSheetId = id;
|
|
96
|
+
selectedCell = 'A1';
|
|
234
97
|
onchange?.(sheets);
|
|
235
98
|
}
|
|
236
99
|
</script>
|
|
237
100
|
|
|
238
|
-
<div class={cn('svadmin-u-a217b4eaa918 svadmin-u-ca6bcd4b6f3f svadmin-u-18049387f0af svadmin-u-cd0ad9a56558 svadmin-u-cef5b893cf23 svadmin-u-359090c2d529 svadmin-u-6f7e013d6499 svadmin-u-eb6e8b881acd svadmin-u-2cd02d11d1af', className)}>
|
|
239
|
-
<!-- Header Toolbar -->
|
|
101
|
+
<div data-testid="spreadsheet-view" class={cn('svadmin-u-a217b4eaa918 svadmin-u-ca6bcd4b6f3f svadmin-u-18049387f0af svadmin-u-cd0ad9a56558 svadmin-u-cef5b893cf23 svadmin-u-359090c2d529 svadmin-u-6f7e013d6499 svadmin-u-eb6e8b881acd svadmin-u-2cd02d11d1af', className)}>
|
|
240
102
|
<div class="svadmin-u-60fbb7713999 svadmin-u-1eb5c6df38c1 svadmin-u-3960ffc248d9 svadmin-u-8ef2268efbbc svadmin-u-77a2a20e90d4 svadmin-u-f4cc511ff0c1 svadmin-u-65fdbade2025 svadmin-u-05faf5c801ff">
|
|
241
103
|
<div class="svadmin-u-60fbb7713999 svadmin-u-3960ffc248d9 svadmin-u-77a2a20e90d4">
|
|
242
|
-
<FileSpreadsheet class="svadmin-u-11e59c6d5f6b svadmin-u-dc7972ebf3f3 svadmin-u-20aaf08a7ed1 svadmin-u-012fbd121f37" />
|
|
104
|
+
<FileSpreadsheet class="svadmin-u-11e59c6d5f6b svadmin-u-dc7972ebf3f3 svadmin-u-20aaf08a7ed1 svadmin-u-012fbd121f37" aria-hidden="true" />
|
|
243
105
|
<span class="svadmin-u-e83a7042bc91 svadmin-u-d4108abe6359">{currentSheet?.name ?? 'Spreadsheet'}</span>
|
|
244
106
|
</div>
|
|
245
|
-
|
|
246
107
|
<div class="svadmin-u-60fbb7713999 svadmin-u-3960ffc248d9 svadmin-u-58284b4ea568">
|
|
247
108
|
{#if !readonly}
|
|
248
|
-
<Button variant="outline" size="sm" class="svadmin-u-d0a52b312f7d svadmin-u-359090c2d529 svadmin-u-44ee8ba0a421" onclick={addRow}>
|
|
249
|
-
|
|
250
|
-
Row
|
|
251
|
-
</Button>
|
|
252
|
-
<Button variant="outline" size="sm" class="svadmin-u-d0a52b312f7d svadmin-u-359090c2d529 svadmin-u-44ee8ba0a421" onclick={addCol}>
|
|
253
|
-
<Plus class="svadmin-u-6a60c09e6aaa svadmin-u-9cea05671a29" />
|
|
254
|
-
Column
|
|
255
|
-
</Button>
|
|
109
|
+
<Button type="button" variant="outline" size="sm" class="svadmin-u-d0a52b312f7d svadmin-u-359090c2d529 svadmin-u-44ee8ba0a421" onclick={addRow}><Plus size={14} aria-hidden="true" />Row</Button>
|
|
110
|
+
<Button type="button" variant="outline" size="sm" class="svadmin-u-d0a52b312f7d svadmin-u-359090c2d529 svadmin-u-44ee8ba0a421" onclick={addCol}><Plus size={14} aria-hidden="true" />Column</Button>
|
|
256
111
|
{/if}
|
|
257
|
-
|
|
258
|
-
<Button size="sm" class="svadmin-u-d0a52b312f7d svadmin-u-359090c2d529 svadmin-u-44ee8ba0a421" onclick={exportCsv}>
|
|
259
|
-
<Download class="svadmin-u-6a60c09e6aaa svadmin-u-9cea05671a29" />
|
|
260
|
-
Export CSV
|
|
261
|
-
</Button>
|
|
112
|
+
<Button type="button" size="sm" class="svadmin-u-d0a52b312f7d svadmin-u-359090c2d529 svadmin-u-44ee8ba0a421" onclick={exportCsv}><Download size={14} aria-hidden="true" />Export CSV</Button>
|
|
262
113
|
</div>
|
|
263
114
|
</div>
|
|
264
|
-
|
|
265
|
-
<!-- Formula Bar -->
|
|
266
115
|
<div class="svadmin-u-60fbb7713999 svadmin-u-3960ffc248d9 svadmin-u-77a2a20e90d4 svadmin-u-d5eab218aa34 svadmin-u-ec0091ee009b svadmin-u-5f22e64f2282 svadmin-u-b00f43c30c2b svadmin-u-ca6bcd4b6f3f svadmin-u-05faf5c801ff svadmin-u-0e65706bcccd">
|
|
267
|
-
<div class="svadmin-u-d5eab218aa34 svadmin-u-465609a240a8 svadmin-u-07389a777c1f svadmin-u-e6f9e383a762 svadmin-u-ca6bcd4b6f3f svadmin-u-18049387f0af svadmin-u-d4108abe6359 svadmin-u-e83a7042bc91 svadmin-u-d058ca6de60f svadmin-u-28ae52cc20ae svadmin-u-ca6bf63030aa">
|
|
268
|
-
{selectedCell}
|
|
269
|
-
</div>
|
|
116
|
+
<div class="svadmin-u-d5eab218aa34 svadmin-u-465609a240a8 svadmin-u-07389a777c1f svadmin-u-e6f9e383a762 svadmin-u-ca6bcd4b6f3f svadmin-u-18049387f0af svadmin-u-d4108abe6359 svadmin-u-e83a7042bc91 svadmin-u-d058ca6de60f svadmin-u-28ae52cc20ae svadmin-u-ca6bf63030aa">{selectedCell}</div>
|
|
270
117
|
<span class="svadmin-u-bfa603190748 svadmin-u-359090c2d529">fx</span>
|
|
271
|
-
<input
|
|
272
|
-
type="text"
|
|
273
|
-
bind:value={formulaInput}
|
|
274
|
-
{readonly}
|
|
275
|
-
placeholder="Value or formula, e.g. =SUM(B2:E2)"
|
|
118
|
+
<input type="text" value={formulaInput} {readonly} aria-label={`Formula ${selectedCell}`} placeholder="Value or formula, e.g. =SUM(B2:E2)"
|
|
276
119
|
class="svadmin-u-36e579c0b41c svadmin-u-f6fe902450dc svadmin-u-7f19cdf4c5bb svadmin-u-119b2aa0b8f6 svadmin-u-d8e0e382c67b svadmin-u-359090c2d529 svadmin-u-d4108abe6359 svadmin-u-f10f771f87e9 svadmin-u-35ca6b75d707 svadmin-u-0e65706bcccd"
|
|
277
|
-
oninput={
|
|
278
|
-
onkeydown={(
|
|
279
|
-
/>
|
|
120
|
+
oninput={(event) => updateCellValue(selectedCell, event.currentTarget.value)}
|
|
121
|
+
onkeydown={(event) => { if (event.key === 'Enter') { event.preventDefault(); updateCellValue(selectedCell, event.currentTarget.value); } }} />
|
|
280
122
|
</div>
|
|
281
|
-
|
|
282
|
-
<!-- Spreadsheet Grid -->
|
|
283
123
|
{#if currentSheet}
|
|
284
124
|
<div class="svadmin-u-73fc3fb18ceb svadmin-u-b63b7d8eef5d svadmin-u-ca6bcd4b6f3f svadmin-u-05faf5c801ff svadmin-u-5f22e64f2282">
|
|
285
|
-
<table class="svadmin-u-6da6a3c3f741 svadmin-u-4583f90cd9bd svadmin-u-2eba0d65d059 svadmin-u-0e65706bcccd">
|
|
286
|
-
<thead class="svadmin-u-706701550477 svadmin-u-3e0fd166d494 svadmin-u-2167406b24d7 svadmin-u-236812d64c82 svadmin-u-bfa603190748">
|
|
287
|
-
<
|
|
288
|
-
|
|
289
|
-
|
|
290
|
-
<th class="svadmin-u-25effcb585ab svadmin-u-cd009d7d208c svadmin-u-ca6bf63030aa svadmin-u-5ceb636bd9f3 svadmin-u-65fdbade2025 svadmin-u-05faf5c801ff svadmin-u-e83a7042bc91 svadmin-u-d4108abe6359 svadmin-u-359090c2d529">
|
|
291
|
-
{getColName(c)}
|
|
292
|
-
</th>
|
|
293
|
-
{/each}
|
|
294
|
-
</tr>
|
|
295
|
-
</thead>
|
|
125
|
+
<table aria-label={currentSheet.name} class="svadmin-u-6da6a3c3f741 svadmin-u-4583f90cd9bd svadmin-u-2eba0d65d059 svadmin-u-0e65706bcccd">
|
|
126
|
+
<thead class="svadmin-u-706701550477 svadmin-u-3e0fd166d494 svadmin-u-2167406b24d7 svadmin-u-236812d64c82 svadmin-u-bfa603190748"><tr>
|
|
127
|
+
<th class="svadmin-u-d854e5698b57 svadmin-u-cd009d7d208c svadmin-u-ca6bf63030aa svadmin-u-5ceb636bd9f3 svadmin-u-65fdbade2025 svadmin-u-05faf5c801ff svadmin-u-85d919893645 svadmin-u-1dc571a3609f">#</th>
|
|
128
|
+
{#each Array.from({ length: currentSheet.cols }) as _, column (column)}<th scope="col" class="svadmin-u-25effcb585ab svadmin-u-cd009d7d208c svadmin-u-ca6bf63030aa svadmin-u-5ceb636bd9f3 svadmin-u-65fdbade2025 svadmin-u-05faf5c801ff svadmin-u-e83a7042bc91 svadmin-u-d4108abe6359 svadmin-u-359090c2d529">{getColName(column)}</th>{/each}
|
|
129
|
+
</tr></thead>
|
|
296
130
|
<tbody class="svadmin-u-fa6acbf81d74 svadmin-u-08b5607c7258">
|
|
297
|
-
{#each Array.from({ length: currentSheet.rows }) as _,
|
|
298
|
-
{@const rowNum = r + 1}
|
|
131
|
+
{#each Array.from({ length: currentSheet.rows }) as _, row (row)}
|
|
299
132
|
<tr class="svadmin-u-9fc5d875f5ca">
|
|
300
|
-
<td class="svadmin-u-d854e5698b57 svadmin-u-eb6a3cef9686 svadmin-u-ca6bf63030aa svadmin-u-5ceb636bd9f3 svadmin-u-05faf5c801ff svadmin-u-2859c861d7de svadmin-u-1dc571a3609f svadmin-u-e83a7042bc91 svadmin-u-bfa603190748 svadmin-u-7f6912283f11">
|
|
301
|
-
|
|
302
|
-
|
|
303
|
-
|
|
304
|
-
{
|
|
305
|
-
|
|
306
|
-
|
|
307
|
-
|
|
308
|
-
'svadmin-u-8a539c7fe216 svadmin-u-5ceb636bd9f3 svadmin-u-6ee2d41e2d2d svadmin-u-d89972fe17d6 svadmin-u-34516836730d',
|
|
309
|
-
isSelected ? 'svadmin-u-16b1efa5875e svadmin-u-fd1dda07320a svadmin-u-236812d64c82 svadmin-u-989c466fdbe7' : ''
|
|
310
|
-
)}
|
|
311
|
-
onclick={() => selectCell(cellKey)}
|
|
312
|
-
>
|
|
313
|
-
<input
|
|
314
|
-
type="text"
|
|
315
|
-
{readonly}
|
|
316
|
-
value={isSelected ? (currentSheet.cells[cellKey] ?? '') : getRenderedValue(cellKey)}
|
|
317
|
-
class={cn(
|
|
318
|
-
'svadmin-u-6da6a3c3f741 svadmin-u-d0a52b312f7d svadmin-u-d5eab218aa34 svadmin-u-7f19cdf4c5bb svadmin-u-119b2aa0b8f6 svadmin-u-359090c2d529 svadmin-u-0e65706bcccd svadmin-u-f10f771f87e9',
|
|
319
|
-
typeof evaluateFormula(currentSheet.cells[cellKey] ?? '', currentSheet.cells) === 'number' ? 'svadmin-u-308fc069e46e' : 'svadmin-u-2eba0d65d059'
|
|
320
|
-
)}
|
|
321
|
-
onfocus={() => selectCell(cellKey)}
|
|
322
|
-
oninput={(e) => updateCellValue(cellKey, e.currentTarget.value)}
|
|
323
|
-
/>
|
|
133
|
+
<td class="svadmin-u-d854e5698b57 svadmin-u-eb6a3cef9686 svadmin-u-ca6bf63030aa svadmin-u-5ceb636bd9f3 svadmin-u-05faf5c801ff svadmin-u-2859c861d7de svadmin-u-1dc571a3609f svadmin-u-e83a7042bc91 svadmin-u-bfa603190748 svadmin-u-7f6912283f11">{row + 1}</td>
|
|
134
|
+
{#each Array.from({ length: currentSheet.cols }) as _, column (column)}
|
|
135
|
+
{@const cellKey = `${getColName(column)}${row + 1}`}
|
|
136
|
+
{@const selected = selectedCell === cellKey}
|
|
137
|
+
<td class={cn('svadmin-u-8a539c7fe216 svadmin-u-5ceb636bd9f3 svadmin-u-6ee2d41e2d2d svadmin-u-d89972fe17d6 svadmin-u-34516836730d', selected ? 'svadmin-u-16b1efa5875e svadmin-u-fd1dda07320a svadmin-u-236812d64c82 svadmin-u-989c466fdbe7' : '')} onclick={() => selectCell(cellKey)}>
|
|
138
|
+
<input type="text" {readonly} aria-label={`Cell ${cellKey}`} value={selected ? currentSheet.cells[cellKey] ?? '' : getRenderedValue(cellKey)}
|
|
139
|
+
class={cn('svadmin-u-6da6a3c3f741 svadmin-u-d0a52b312f7d svadmin-u-d5eab218aa34 svadmin-u-7f19cdf4c5bb svadmin-u-119b2aa0b8f6 svadmin-u-359090c2d529 svadmin-u-0e65706bcccd svadmin-u-f10f771f87e9', typeof evaluateFormula(currentSheet.cells[cellKey] ?? '', currentSheet.cells) === 'number' ? 'svadmin-u-308fc069e46e' : 'svadmin-u-2eba0d65d059')}
|
|
140
|
+
onfocus={() => selectCell(cellKey)} oninput={(event) => updateCellValue(cellKey, event.currentTarget.value)} />
|
|
324
141
|
</td>
|
|
325
142
|
{/each}
|
|
326
143
|
</tr>
|
|
@@ -329,35 +146,13 @@
|
|
|
329
146
|
</table>
|
|
330
147
|
</div>
|
|
331
148
|
{/if}
|
|
332
|
-
|
|
333
|
-
<!-- Sheet Tabs Footer -->
|
|
334
149
|
<div class="svadmin-u-60fbb7713999 svadmin-u-3960ffc248d9 svadmin-u-8ef2268efbbc svadmin-u-77a2a20e90d4 svadmin-u-6b7d6e21ccbd svadmin-u-b950dda299d3 svadmin-u-05faf5c801ff">
|
|
335
150
|
<div class="svadmin-u-60fbb7713999 svadmin-u-3960ffc248d9 svadmin-u-44ee8ba0a421 svadmin-u-1384f66f41d0">
|
|
336
151
|
{#each sheets as sheet (sheet.id)}
|
|
337
|
-
|
|
338
|
-
|
|
339
|
-
type="button"
|
|
340
|
-
class={cn(
|
|
341
|
-
'svadmin-u-0e17f2bd9074 svadmin-u-660d2effb880 svadmin-u-421ac2be5045 svadmin-u-359090c2d529 svadmin-u-2689f3958069 svadmin-u-ceb69a6b0e5f svadmin-u-34516836730d svadmin-u-ca6bcd4b6f3f',
|
|
342
|
-
isActive
|
|
343
|
-
? 'svadmin-u-75b1bec3ea0e svadmin-u-30ca335ae9c2 svadmin-u-6cbc84dd9e1a svadmin-u-cef5b893cf23'
|
|
344
|
-
: 'svadmin-u-cd0ad9a56558 svadmin-u-bfa603190748 svadmin-u-05faf5c801ff svadmin-u-ea7b2e9e070e svadmin-u-68646cdcc246'
|
|
345
|
-
)}
|
|
346
|
-
onclick={() => {
|
|
347
|
-
activeSheetId = sheet.id;
|
|
348
|
-
selectedCell = 'A1';
|
|
349
|
-
formulaInput = sheet.cells['A1'] ?? '';
|
|
350
|
-
}}
|
|
351
|
-
>
|
|
352
|
-
{sheet.name}
|
|
353
|
-
</button>
|
|
152
|
+
<button type="button" class={cn('svadmin-u-0e17f2bd9074 svadmin-u-660d2effb880 svadmin-u-421ac2be5045 svadmin-u-359090c2d529 svadmin-u-2689f3958069 svadmin-u-ceb69a6b0e5f svadmin-u-34516836730d svadmin-u-ca6bcd4b6f3f', sheet.id === activeSheetId ? 'svadmin-u-75b1bec3ea0e svadmin-u-30ca335ae9c2 svadmin-u-6cbc84dd9e1a svadmin-u-cef5b893cf23' : 'svadmin-u-cd0ad9a56558 svadmin-u-bfa603190748 svadmin-u-05faf5c801ff svadmin-u-ea7b2e9e070e svadmin-u-68646cdcc246')}
|
|
153
|
+
onclick={() => { activeSheetId = sheet.id; selectedCell = 'A1'; }}>{sheet.name}</button>
|
|
354
154
|
{/each}
|
|
355
|
-
|
|
356
|
-
{#if !readonly}
|
|
357
|
-
<Button variant="ghost" size="sm" class="svadmin-u-f6fe902450dc svadmin-u-7ec10f86d9b1 svadmin-u-8a539c7fe216 svadmin-u-bfa603190748" onclick={addSheet} title="New Sheet">
|
|
358
|
-
<Plus class="svadmin-u-7fc7f732bf7e svadmin-u-bf600f8e029c" />
|
|
359
|
-
</Button>
|
|
360
|
-
{/if}
|
|
155
|
+
{#if !readonly}<Button type="button" variant="ghost" size="sm" class="svadmin-u-f6fe902450dc svadmin-u-7ec10f86d9b1 svadmin-u-8a539c7fe216 svadmin-u-bfa603190748" onclick={addSheet} title="New Sheet" aria-label="New Sheet"><Plus size={14} aria-hidden="true" /></Button>{/if}
|
|
361
156
|
</div>
|
|
362
157
|
</div>
|
|
363
158
|
</div>
|
|
@@ -229,10 +229,10 @@
|
|
|
229
229
|
>
|
|
230
230
|
<span
|
|
231
231
|
class="svadmin-u-60fbb7713999 svadmin-u-d0a52b312f7d svadmin-u-cbbf90f9a828 svadmin-u-3960ffc248d9 svadmin-u-86843cf1e227 svadmin-u-ac204c108886 svadmin-u-359090c2d529 svadmin-u-2689f3958069 svadmin-u-ceb69a6b0e5f"
|
|
232
|
-
class:
|
|
233
|
-
class:
|
|
234
|
-
class:
|
|
235
|
-
class:
|
|
232
|
+
class:svadmin-u-75b1bec3ea0e={i <= form.steps.currentStep}
|
|
233
|
+
class:svadmin-u-30ca335ae9c2={i <= form.steps.currentStep}
|
|
234
|
+
class:svadmin-u-2ef11f1cb219={i > form.steps.currentStep}
|
|
235
|
+
class:svadmin-u-bfa603190748={i > form.steps.currentStep}
|
|
236
236
|
>
|
|
237
237
|
{#if i < form.steps.currentStep}
|
|
238
238
|
<Check class="svadmin-u-7fc7f732bf7e svadmin-u-bf600f8e029c" />
|
|
@@ -243,7 +243,7 @@
|
|
|
243
243
|
<span class="svadmin-u-99d72c7fc3e2 svadmin-u-ee3c1259a368">{step.title}</span>
|
|
244
244
|
</Button>
|
|
245
245
|
{#if i < steps.length - 1}
|
|
246
|
-
<div class="svadmin-u-36e579c0b41c svadmin-u-9e10c04e17bb svadmin-u-aea6160836e7 svadmin-u-a59afa8d9b9d" class:
|
|
246
|
+
<div class="svadmin-u-36e579c0b41c svadmin-u-9e10c04e17bb svadmin-u-aea6160836e7 svadmin-u-a59afa8d9b9d" class:svadmin-u-75b1bec3ea0e={i < form.steps.currentStep}></div>
|
|
247
247
|
{/if}
|
|
248
248
|
{/each}
|
|
249
249
|
</div>
|
|
@@ -0,0 +1,39 @@
|
|
|
1
|
+
<script lang="ts">
|
|
2
|
+
import type { ComponentProps } from 'svelte';
|
|
3
|
+
import { captureAdminContext, captureAuthSession } from '@svadmin/core';
|
|
4
|
+
import AutoTable from './AutoTable.svelte';
|
|
5
|
+
import SvarDataGrid from './SvarDataGrid.svelte';
|
|
6
|
+
export type SvarAutoTableProps = Omit<ComponentProps<typeof AutoTable>, 'gridBody'> & {
|
|
7
|
+
Grid: ComponentProps<typeof SvarDataGrid>['Grid'];
|
|
8
|
+
Theme: ComponentProps<typeof SvarDataGrid>['Theme'];
|
|
9
|
+
height?: number;
|
|
10
|
+
freezeLeft?: number;
|
|
11
|
+
freezeRight?: number;
|
|
12
|
+
};
|
|
13
|
+
let { Grid, Theme, height = 420, freezeLeft = 0, freezeRight = 0, ...props }: SvarAutoTableProps = $props();
|
|
14
|
+
const context = captureAdminContext();
|
|
15
|
+
const owner = $derived.by(() => {
|
|
16
|
+
const auth = captureAuthSession(context.authProvider);
|
|
17
|
+
return { resource: props.resourceName, contract: context.getResource(props.resourceName).contract,
|
|
18
|
+
provider: context.getDataProviderForResource(props.resourceName), access: context.accessControlProvider,
|
|
19
|
+
tenant: context.tenantCacheKey?.__svadminTenant, authKey: auth.cacheKey, available: auth.available };
|
|
20
|
+
});
|
|
21
|
+
</script>
|
|
22
|
+
|
|
23
|
+
{#key owner}
|
|
24
|
+
{#if owner.available}
|
|
25
|
+
<AutoTable {...props}>
|
|
26
|
+
{#snippet gridBody(state)}
|
|
27
|
+
<details><summary>{state.locale.startsWith('zh') ? '表格选择与列顺序' : 'Selection and column order'}</summary>{@render state.controls()}</details>
|
|
28
|
+
<SvarDataGrid {Grid} {Theme} items={state.records} columns={state.columns} primaryKey={state.primaryKey}
|
|
29
|
+
{height} freezeLeft={Math.min(freezeLeft, state.columns.length - Math.min(freezeRight, state.columns.length - 1))}
|
|
30
|
+
freezeRight={Math.min(freezeRight, state.columns.length - 1)} density={state.density}
|
|
31
|
+
queryMode="server" sorters={state.sorters} onSortChange={state.onSortChange}
|
|
32
|
+
disabled={state.disabled} scopeKey={state.scopeKey} locale={state.locale} label={state.label}>
|
|
33
|
+
{#snippet cellContent({ id, field })}{@render state.cell({ id, field })}{/snippet}
|
|
34
|
+
</SvarDataGrid>
|
|
35
|
+
{@render state.after()}
|
|
36
|
+
{/snippet}
|
|
37
|
+
</AutoTable>
|
|
38
|
+
{/if}
|
|
39
|
+
{/key}
|
|
@@ -0,0 +1,13 @@
|
|
|
1
|
+
import type { ComponentProps } from 'svelte';
|
|
2
|
+
import AutoTable from './AutoTable.svelte';
|
|
3
|
+
import SvarDataGrid from './SvarDataGrid.svelte';
|
|
4
|
+
export type SvarAutoTableProps = Omit<ComponentProps<typeof AutoTable>, 'gridBody'> & {
|
|
5
|
+
Grid: ComponentProps<typeof SvarDataGrid>['Grid'];
|
|
6
|
+
Theme: ComponentProps<typeof SvarDataGrid>['Theme'];
|
|
7
|
+
height?: number;
|
|
8
|
+
freezeLeft?: number;
|
|
9
|
+
freezeRight?: number;
|
|
10
|
+
};
|
|
11
|
+
declare const SvarAutoTable: import("svelte").Component<SvarAutoTableProps, {}, "">;
|
|
12
|
+
type SvarAutoTable = ReturnType<typeof SvarAutoTable>;
|
|
13
|
+
export default SvarAutoTable;
|