Skip to content

Commit

Permalink
Feature/1507 grid apply tokens (#1550)
Browse files Browse the repository at this point in the history
* added spacing tokans to primitives and grid color tokens to SL light

* edited sl llgiht colors

* first tokens

* added column divider

* Added spacing tokens to primitives and fixed missing tokens after merge from main

* column divider

* hover state

* selected colour

* renamed stories

* change the way selection works (#1548)

* change the way selection works

* added changeset

* added color for group row to sl light new

* fixed primitive space.150

* fixed tests

* cleanup

* fix height, review comments

* updated icons

* fix 0 instead of 0px

* trigger chromatic screenshots

* update yarnlock

---------

Co-authored-by: RoaldBoerema <[email protected]>
  • Loading branch information
Diaan and RoaldBoerema authored Oct 28, 2024
1 parent 515e2fb commit ac23d84
Show file tree
Hide file tree
Showing 38 changed files with 333 additions and 142 deletions.
5 changes: 5 additions & 0 deletions .changeset/soft-coins-shop.md
Original file line number Diff line number Diff line change
@@ -0,0 +1,5 @@
---
'@sl-design-system/grid': patch
---

Changed the way selection works; there are now 2 distinct functionalities; selecting one or more rows with checkboxes, for bulk actions for example and clicking and highlighting an entire row as a way of selecting it for a detailed view for example
1 change: 1 addition & 0 deletions grid-poc
Submodule grid-poc added at a55a9c
2 changes: 1 addition & 1 deletion package.json
Original file line number Diff line number Diff line change
Expand Up @@ -463,7 +463,7 @@
"husky": "^9.1.5",
"lint-staged": "^15.2.10",
"lit": "^3.1.4",
"sinon": "^18.0.0",
"sinon": "^18.0.1",
"storybook": "^8.2.9",
"stylelint": "^16.9.0",
"typescript": "^5.4.5",
Expand Down
2 changes: 1 addition & 1 deletion packages/components/card/src/card.stories.ts
Original file line number Diff line number Diff line change
Expand Up @@ -73,7 +73,7 @@ export default {
cardIcon
}) => html`
<sl-card .orientation=${orientation}>
${media && imageUrl ? html`<img slot="media" src=${imageUrl} />` : nothing}
${media && imageUrl ? html`<img slot="media" src=${imageUrl} alt="Picture of ${title}" />` : nothing}
${cardIcon ? html`<sl-icon .name=${cardIcon} slot="icon"></sl-icon>` : nothing}
<h2>${title}</h2>
${subheaderContent
Expand Down
21 changes: 5 additions & 16 deletions packages/components/grid/src/column-group.spec.ts
Original file line number Diff line number Diff line change
@@ -1,5 +1,6 @@
import { setupIgnoreWindowResizeObserverLoopErrors } from '@lit-labs/virtualizer/support/resize-observer-errors.js';
import { expect, fixture } from '@open-wc/testing';
import { setViewport } from '@web/test-runner-commands';
import { html } from 'lit';
import '../register.js';
import { type Grid } from './grid.js';
Expand All @@ -25,6 +26,7 @@ describe('sl-column-group', () => {
</sl-grid-column-group>
</sl-grid>
`);
await setViewport({ width: 1024, height: 1024 });
el.items = [{ firstName: 'John', lastName: 'Doe', grades: { biology: 'A', maths: 'B', english: 'B+' } }];
await el.updateComplete;

Expand All @@ -51,23 +53,9 @@ describe('sl-column-group', () => {
it('should have the correct width', () => {
const cells = Array.from(el.renderRoot.querySelectorAll('th'));
expect(cells.map(cell => Math.floor(parseFloat(getComputedStyle(cell).width)))).to.deep.equal([
300, 481, 151, 148, 128, 120, 128, 103
369, 636, 185, 183, 169, 157, 166, 144
]);
});

// it('should emit an sl-column-update event after clicking the checkbox', async () => {
// const columnUpdateEvent = spy();
// const columnGoup = el.querySelector('sl-grid-column-group:first-of-type') as GridColumnGroup;
// columnGoup?.addEventListener('sl-column-update', columnUpdateEvent);

// const newColumn = document.createElement('sl-grid-column');
// await new Promise(resolve => setTimeout(resolve, 100));

// columnGoup?.appendChild(newColumn);

// // expect(columnUpdateEvent).to.have.been.called;
// expect(columnGoup?.columns).to.equal(3);
// });
});

describe('explicit width', () => {
Expand All @@ -85,6 +73,7 @@ describe('sl-column-group', () => {
</sl-grid-column-group>
</sl-grid>
`);
await setViewport({ width: 1024, height: 1024 });

el.items = [{ firstName: 'John', lastName: 'Doe', grades: { biology: 'A', maths: 'B', english: 'B+' } }];
await el.updateComplete;
Expand All @@ -97,7 +86,7 @@ describe('sl-column-group', () => {
it('should have the correct width when one is set explicitly', () => {
const cells = Array.from(el.renderRoot.querySelectorAll('th'));
expect(cells.map(cell => Math.floor(parseFloat(getComputedStyle(cell).width)))).to.deep.equal([
209, 600, 177, 175, 155, 147, 155
281, 724, 214, 212, 197, 186, 195
]);
});
});
Expand Down
76 changes: 56 additions & 20 deletions packages/components/grid/src/grid.scss
Original file line number Diff line number Diff line change
@@ -1,27 +1,28 @@
// stylelint-disable color-no-hex
:host {
--_border: var(--_border-width) solid var(--_border-color);
--_border-color: #eee;
--_border-width: 1px;
--_border-radius: 3px;
--_cell-background: #fff;
--_cell-border: 1px solid #eee;
--_cell-padding-block: 0.5rem;
--_cell-padding-inline: 1rem;
--_border-color: var(--sl-color-grid-border);
--_border-width: var(--sl-size-borderWidth-default);
--_border-radius: var(--sl-size-borderRadius-default);
--_cell-background: var(--sl-color-grid-default);
--_cell-border: var(--_border-width) solid var(--_border-color);
--_cell-padding-block: var(--sl-space-175);
--_cell-padding-inline: var(--sl-space-200);
--_drag-handle-inline-size: 28px;
--_dragging-background: #ddeffe;
--_dragging-border: var(--_border-width) solid #056dc2;
--_dragging-opacity: 0.8;
--_drop-target-outline: 2px solid #056dc2;
--_drop-target-outline-offset: -2px;
--_font: var(--sl-text-body-md-normal);
--_group-background: #eee;
--_header-background: #f9f9f9;
--_header-font-weight: 600;
--_header-padding-block: 0.5rem;
--_header-padding-inline: 1rem;
--_selected-background: #338bff0f;
--_striped-background: #f9f9f9;
--_group-background: var(--sl-color-grid-group);
--_header-background: var(--sl-color-grid-header);
--_header-padding-block: var(--sl-space-175);
--_header-padding-inline: var(--sl-space-200);
--_vertical-border: none;
--_vertical-border-offset: var(--sl-space-new-md);
--_selected-background: var(--sl-color-action-background-accent-subtle-active);
--_striped-background: var(--sl-color-grid-zebra);

display: block;
font: var(--_font);
Expand All @@ -39,6 +40,22 @@
--_cell-border: none;
}

:host([column-divider]) {
// this is needed because we need to set the vertical-border-offset separately for the th,
// when this is set on a highter level than the `--_vertical-border-offset` var it can't "reach" it.
td,
th {
--_vertical-border-offset: 0px;
--_vertical-border: linear-gradient(var(--_border-color), var(--_border-color)) 0
calc(100% - var(--_vertical-border-offset)) / var(--_border-width) calc(100% - var(--_vertical-border-offset) * 2)
no-repeat;

&:first-of-type {
--_vertical-border: none;
}
}
}

:host([striped]) tr[part~='even'] {
--_cell-background: var(--_striped-background);
}
Expand Down Expand Up @@ -117,10 +134,6 @@ tr {
}
}

&[part~='selected'] {
--_cell-background: var(--_selected-background);
}

&.drop-target {
outline: var(--_drop-target-outline);
outline-offset: var(--_drop-target-outline-offset);
Expand All @@ -130,11 +143,12 @@ tr {
th,
td {
align-items: center;
background: var(--_cell-background);
background: var(--_vertical-border), var(--_cell-background);
box-sizing: border-box;
display: inline-flex;
flex-shrink: 0;
overflow: hidden;
overflow: clip;
overflow-clip-margin: content-box 0;
padding: var(--_cell-padding-block) var(--_cell-padding-inline);

&:first-of-type:not([part~='drag-handle']) {
Expand All @@ -153,9 +167,16 @@ th {
--_cell-background: var(--_header-background);
--_cell-padding-block: var(--_header-padding-block);
--_cell-padding-inline: var(--_header-padding-inline);
--_vertical-border: linear-gradient(var(--_border-color), var(--_border-color)) 0
calc(100% - var(--_vertical-border-offset)) / var(--_border-width) calc(100% - var(--_vertical-border-offset) * 2)
no-repeat;

font-weight: var(--_header-font-weight);
text-align: start;

&:first-of-type {
--_vertical-border: none;
}
}

th[part~='drag-handle'] {
Expand Down Expand Up @@ -213,6 +234,21 @@ td[part~='text-field'] {
font-weight: 600;
}

:host([clickable-row]) {
[part~='row'] {
cursor: pointer;

&:hover {
--_cell-background: var(--sl-color-action-background-accent-subtle-hover);
}
}

tr[part~='row']:active,
tr[part~='active'] {
--_cell-background: var(--_selected-background);
}
}

.selection-count {
font-weight: normal;
}
Expand Down
21 changes: 14 additions & 7 deletions packages/components/grid/src/grid.ts
Original file line number Diff line number Diff line change
Expand Up @@ -66,7 +66,7 @@ export type GridGroupHeaderRenderer = (
) => TemplateResult;

// eslint-disable-next-line @typescript-eslint/no-explicit-any
export type SlActiveItemChangeEvent<T = any> = CustomEvent<{ grid: Grid<T>; item: T; relatedEvent?: Event }>;
export type SlActiveItemChangeEvent<T = any> = CustomEvent<{ grid: Grid<T>; item?: T; relatedEvent?: Event }>;

// eslint-disable-next-line @typescript-eslint/no-explicit-any
export type SlDragStartEvent<T = any> = CustomEvent<{ grid: Grid<T>; item: T }>;
Expand Down Expand Up @@ -177,6 +177,9 @@ export class Grid<T = any> extends ScopedElementsMixin(LitElement) {
/** @internal Emits when an item has been dropped. */
@event({ name: 'sl-grid-drop', cancelable: true }) dropEvent!: EventEmitter<SlDropEvent<T>>;

/** Whether a row can be set active by clicking anywhere in the row. */
@property({ type: Boolean, reflect: true, attribute: 'clickable-row' }) clickableRow?: boolean;

/**
* Determines if or what kind of drop target the given item is:
* - boolean: the item is valid drop target based on the draggableRows value
Expand Down Expand Up @@ -392,11 +395,11 @@ export class Grid<T = any> extends ScopedElementsMixin(LitElement) {

renderItemRow(item: T, index: number): TemplateResult {
const rows = this.view.headerRows,
selected = this.selection.isSelected(item),
active = this.selection.isActive(item),
parts = [
'row',
index % 2 === 0 ? 'odd' : 'even',
...(selected ? ['selected'] : []),
...(active ? ['active'] : []),
...(this.#dragItem === item ? ['dragging'] : []),
...(this.itemParts?.(item)?.split(' ') || []),
...(this.view.isFixedItem(item) ? ['fixed'] : [])
Expand All @@ -410,7 +413,7 @@ export class Grid<T = any> extends ScopedElementsMixin(LitElement) {
@dragover=${(event: DragEvent) => this.#onDragOver(event, item)}
@dragend=${(event: DragEvent) => this.#onDragEnd(event, item)}
@drop=${(event: DragEvent) => this.#onDrop(event, item)}
class=${classMap({ selected })}
class=${classMap({ active })}
part=${parts.join(' ')}
index=${index}
>
Expand All @@ -422,7 +425,8 @@ export class Grid<T = any> extends ScopedElementsMixin(LitElement) {
renderGroupRow(group: GridViewModelGroup, index: number): TemplateResult {
const expanded = this.view.getGroupState(group.value),
selectable = !!this.view.columns.find(col => col instanceof GridSelectionColumn),
selected = this.view.getGroupSelection(group.value);
selected = this.view.getGroupSelection(group.value),
active = this.view.getActiveRow(group.value);

return html`
<tr part="group" index=${index}>
Expand All @@ -433,6 +437,7 @@ export class Grid<T = any> extends ScopedElementsMixin(LitElement) {
.expanded=${expanded}
.selectable=${selectable}
.selected=${selected}
.active=${active}
>
${this.groupHeaderRenderer?.(group) ?? html`<span part="group-heading">${group.value}</span>`}
</sl-grid-group-header>
Expand Down Expand Up @@ -475,8 +480,10 @@ export class Grid<T = any> extends ScopedElementsMixin(LitElement) {
}

#onClickRow(event: Event, item: T): void {
this.activeItem = item;
this.activeItemChangeEvent.emit({ grid: this, item: this.activeItem, relatedEvent: event });
if (this.clickableRow) {
this.activeItem = this.selection.toggleActive(item);
this.activeItemChangeEvent.emit({ grid: this, item: this.activeItem, relatedEvent: event });
}
}

#onColumnUpdate(event: Event & { target: GridColumn<T> }): void {
Expand Down
17 changes: 0 additions & 17 deletions packages/components/grid/src/selection-column.ts
Original file line number Diff line number Diff line change
@@ -1,11 +1,9 @@
import { msg, str } from '@lit/localize';
import { Checkbox } from '@sl-design-system/checkbox';
import { EventsController } from '@sl-design-system/shared';
import { type SlChangeEvent } from '@sl-design-system/shared/events.js';
import { type PropertyValues, type TemplateResult, html } from 'lit';
import { property } from 'lit/decorators.js';
import { GridColumn } from './column.js';
import { type SlActiveItemChangeEvent } from './grid.js';

declare global {
interface HTMLElementTagNameMap {
Expand All @@ -15,8 +13,6 @@ declare global {

// eslint-disable-next-line @typescript-eslint/no-explicit-any
export class GridSelectionColumn<T = any> extends GridColumn<T> {
#events = new EventsController(this);

/** When true, the active rows get selected automatically. */
@property({ type: Boolean, attribute: 'auto-select' }) autoSelect?: boolean;

Expand All @@ -34,8 +30,6 @@ export class GridSelectionColumn<T = any> extends GridColumn<T> {
super.willUpdate(changes);

if (changes.has('grid') && this.grid) {
this.#events.listen(this.grid, 'sl-active-item-change', this.#onActiveItemChange);

this.grid.selection.multiple = true;

if (this.selectAll) {
Expand Down Expand Up @@ -102,17 +96,6 @@ export class GridSelectionColumn<T = any> extends GridColumn<T> {
return result;
}

#onActiveItemChange({ detail: { item, relatedEvent } }: SlActiveItemChangeEvent<T>): void {
const isCheckbox = (relatedEvent?.target as HTMLElement)?.tagName.toLowerCase() === 'sl-checkbox';

if (!this.autoSelect || !item || isCheckbox) {
return;
}

this.selectAll = false;
this.grid?.selection.toggle(item);
}

#onToggleSelect(item: T, checked: boolean): void {
this.selectAll = false;

Expand Down
Loading

0 comments on commit ac23d84

Please sign in to comment.