|
10 | 10 | type SpreadsheetRootProps |
11 | 11 | } from './index.js'; |
12 | 12 | import { tick, onDestroy, createEventDispatcher, type ComponentType } from 'svelte'; |
| 13 | + import { readable } from 'svelte/store'; |
13 | 14 | import { getRowContext } from './context.js'; |
| 15 | + import type { SpreadsheetDOMProps, SpreadsheetRowState } from './index.js'; |
14 | 16 |
|
15 | 17 | export let root: SpreadsheetRootProps; |
16 | 18 | export let value: string | undefined = undefined; |
|
22 | 24 | export let isHeader = false; |
23 | 25 | export let isEditable = true; |
24 | 26 | export let openEditOnTap = false; |
| 27 | + let className = ''; |
| 28 | + export { className as class }; |
| 29 | + let inlineStyle: string | undefined = undefined; |
| 30 | + export { inlineStyle as style }; |
25 | 31 |
|
26 | 32 | let width = 0; |
27 | 33 | let startX = 0; |
|
34 | 40 | let originalValue = value; |
35 | 41 | let rowIndex: number = -1; |
36 | 42 | let rowId: string | undefined = undefined; |
| 43 | + let rowState: SpreadsheetRowState = { |
| 44 | + rowId: undefined, |
| 45 | + rowIndex: undefined, |
| 46 | + hovered: false, |
| 47 | + focused: false, |
| 48 | + selected: false, |
| 49 | + isHeader, |
| 50 | + isEmptyRow: false |
| 51 | + }; |
37 | 52 |
|
38 | 53 | /* edit slot close() triggers blur which calls commitChange, this prevents that */ |
39 | 54 | let isClosingFloatingEditor = false; |
|
50 | 65 | $: hasKeyboardNavigation = root.keyboardNavigation ?? false; |
51 | 66 | $: isAction = options?.isAction ?? false; |
52 | 67 | $: isSelect = (root.allowSelection && column?.includes('__select_')) || false; |
53 | | - $: isFixed = isSelect || isAction || options?.fixed; |
| 68 | + $: stickySide = root.getStickySide(column, isSelect, isAction); |
| 69 | + $: stickyOffset = root.getStickyOffset(column, isSelect, isAction); |
| 70 | + $: isFixed = stickySide !== null; |
54 | 71 | $: endsBeforeFixedRight = column === root.lastColumnBeforeAction; |
55 | 72 | $: resizable = (options?.resizable ?? true) && column !== root.lastResizableColumnId; |
56 | 73 | $: isEditing = root.currentlyEditingCellId === id; |
|
195 | 212 | } |
196 | 213 | }); |
197 | 214 |
|
| 215 | + const rowContext = getRowContext() ?? readable(null); |
| 216 | +
|
| 217 | + $: currentRowContext = rowContext ? $rowContext : null; |
| 218 | + $: rowId = currentRowContext?.id ?? undefined; |
| 219 | + $: rowIndex = currentRowContext?.index ?? -1; |
| 220 | + $: rowState = { |
| 221 | + rowId, |
| 222 | + rowIndex: currentRowContext?.isHeader ? undefined : rowIndex > 0 ? rowIndex - 1 : undefined, |
| 223 | + hovered: currentRowContext?.hovered ?? false, |
| 224 | + focused: currentRowContext?.focused ?? false, |
| 225 | + selected: currentRowContext?.selected ?? false, |
| 226 | + isHeader: currentRowContext?.isHeader ?? isHeader, |
| 227 | + isEmptyRow: currentRowContext?.isEmptyRow ?? isEmptyCell |
| 228 | + }; |
| 229 | + $: cellProps = root.getCellProps(rowId, column, rowState) as SpreadsheetDOMProps | undefined; |
| 230 | + $: mergedClassName = [className, cellProps?.class].filter(Boolean).join(' '); |
| 231 | + $: mergedStyle = [inlineStyle, cellProps?.style].filter(Boolean).join('; '); |
| 232 | +
|
198 | 233 | $: if (hasKeyboardNavigation && typeof cellEl !== 'undefined' && !isEmptyCell) { |
199 | | - const rowContext = getRowContext(); |
200 | | - rowId = rowContext?.id ?? undefined; |
201 | | - rowIndex = rowContext?.index ?? -1; |
202 | 234 | root.registerForNavigation(cellEl, rowIndex, columnIndex); |
203 | 235 | } |
204 | 236 |
|
|
303 | 335 | data-header={isHeader} |
304 | 336 | data-loading={isLoading} |
305 | 337 | data-column-id={column} |
| 338 | + data-sticky-side={stickySide} |
| 339 | + data-row-hovered={rowState.hovered} |
| 340 | + data-row-focused={rowState.focused} |
| 341 | + data-row-selected={rowState.selected} |
306 | 342 | data-editing-mode={isEditing} |
307 | 343 | data-edit-on-tap={openEditOnTap} |
308 | 344 | data-empty-cell={isEmptyCell} |
|
320 | 356 | class:no-end-border={endsBeforeFixedRight} |
321 | 357 | class:dragging-column={isDragging} |
322 | 358 | class:drag-over={isDraggedOver && !isDragging} |
323 | | - style:left={isSelect ? '0' : undefined} |
324 | | - style:right={isAction ? '0' : undefined} |
| 359 | + class={mergedClassName} |
| 360 | + style:left={stickySide === 'left' && stickyOffset !== null |
| 361 | + ? `${stickyOffset}px` |
| 362 | + : undefined} |
| 363 | + style:right={stickySide === 'right' && stickyOffset !== null |
| 364 | + ? `${stickyOffset}px` |
| 365 | + : undefined} |
| 366 | + style={mergedStyle} |
325 | 367 | on:contextmenu={isEmptyCell ? undefined : handleContextMenu} |
326 | 368 | use:clickOutside={handleClickOutside} |
327 | 369 | on:click={handleCellClick} |
|
403 | 445 | font-size: var(--font-size-s); |
404 | 446 | padding: var(--space-4) var(--space-6); |
405 | 447 | background: var(--bgcolor-neutral-primary); |
| 448 | + transition: background-color 125ms ease-in-out; |
406 | 449 |
|
407 | 450 | &[data-select='false'] { |
408 | 451 | box-shadow: 0 -1px 0 0 var(--border-neutral) inset; |
409 | 452 | } |
410 | 453 |
|
| 454 | + &[data-row-selected='true']:not([data-header='true']) { |
| 455 | + background: var(--overlay-neutral-pressed-solid); |
| 456 | + } |
| 457 | +
|
| 458 | + &[data-row-hovered='true'][data-row-focused='false']:not([data-row-selected='true']):not( |
| 459 | + [data-header='true'] |
| 460 | + ) { |
| 461 | + cursor: pointer; |
| 462 | + background: var(--overlay-neutral-hover-solid); |
| 463 | + } |
| 464 | +
|
411 | 465 | &:not([data-header='true'])[data-allow-focus='true']:focus { |
412 | 466 | left: -1px; |
413 | 467 | z-index: 10; |
|
475 | 529 | &:has(textarea) { |
476 | 530 | min-height: 120px; |
477 | 531 | padding-block: 9px; |
| 532 | + resize: none; |
| 533 | + overflow: auto; |
| 534 | +
|
| 535 | + &::after { |
| 536 | + display: none; |
| 537 | + } |
478 | 538 | } |
479 | 539 |
|
480 | 540 | &:not(:has(textarea)) { |
|
577 | 637 | z-index: 10; |
578 | 638 | } |
579 | 639 |
|
580 | | - &[data-select='true'] { |
581 | | - left: 0; |
| 640 | + &[data-sticky-side='left'] { |
582 | 641 | border-right: var(--border-width-s) solid var(--border-neutral); |
583 | | - border-bottom: var(--border-width-s) solid var(--border-neutral); |
584 | 642 | } |
585 | 643 |
|
586 | | - &[data-action='true'] { |
587 | | - right: 0; |
| 644 | + &[data-sticky-side='right'] { |
588 | 645 | display: inline-flex; |
589 | 646 | justify-content: center; |
590 | 647 | border-left: var(--border-width-s) solid var(--border-neutral); |
591 | 648 | } |
| 649 | +
|
| 650 | + &[data-select='true'] { |
| 651 | + border-bottom: var(--border-width-s) solid var(--border-neutral); |
| 652 | + } |
592 | 653 | } |
593 | 654 |
|
594 | 655 | &.space-between { |
|
0 commit comments