Skip to content
Draft
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension


Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
40 changes: 28 additions & 12 deletions dev/vscode-table/shift-table-columns.html
Original file line number Diff line number Diff line change
Expand Up @@ -37,27 +37,21 @@
<h1>Basic example</h1>
<main>
<vscode-demo>
<vscode-table
class="table"
columns='["100px", "200px"]'
min-column-width="50"
resizable
style="margin-left: 200px"
>
<vscode-table class="table" resizable style="margin-left: 200px">
<vscode-table-header slot="header">
<vscode-table-header-cell min-width="30"
<vscode-table-header-cell min-width="30" preferred-width="25"
>Id</vscode-table-header-cell
>
<vscode-table-header-cell min-width="70"
<vscode-table-header-cell min-width="70" preferred-width="50"
>First name</vscode-table-header-cell
>
<vscode-table-header-cell min-width="70"
<vscode-table-header-cell min-width="70" preferred-width="75"
>Last name</vscode-table-header-cell
>
<vscode-table-header-cell min-width="70"
<vscode-table-header-cell min-width="70" preferred-width="auto"
>Email</vscode-table-header-cell
>
<vscode-table-header-cell min-width="70"
<vscode-table-header-cell min-width="70" preferred-width="auto"
>Company</vscode-table-header-cell
>
</vscode-table-header>
Expand Down Expand Up @@ -101,6 +95,28 @@ <h1>Basic example</h1>
</vscode-table-body>
</vscode-table>
</vscode-demo>
<button id="bt-empty">empty table body</button>
<button id="bt-append">Append row</button>
<script type="module">
const btEmpty = document.querySelector('#bt-empty');
const btAppend = document.querySelector('#bt-append');

btEmpty.addEventListener('click', () => {
document.querySelector('vscode-table-body').innerHTML = '';
});

btAppend.addEventListener('click', () => {
const row = document.createElement('vscode-table-row');
row.innerHTML = `
<vscode-table-cell>cell</vscode-table-cell>
<vscode-table-cell>cell</vscode-table-cell>
<vscode-table-cell>cell</vscode-table-cell>
<vscode-table-cell>cell</vscode-table-cell>
<vscode-table-cell>cell</vscode-table-cell>
`;
document.querySelector('vscode-table-body').append(row);
});
</script>
</main>
</body>
</html>
87 changes: 87 additions & 0 deletions dev/vscode-table/test-cases.html
Original file line number Diff line number Diff line change
@@ -0,0 +1,87 @@
<!doctype html>
<html lang="en">
<head>
<meta charset="UTF-8">
<meta name="viewport" content="width=device-width, initial-scale=1.0">
<title>VSCode Elements</title>
<link
rel="stylesheet"
href="/node_modules/@vscode/codicons/dist/codicon.css"
id="vscode-codicon-stylesheet"
>
<script
type="module"
src="/node_modules/@vscode-elements/webview-playground/dist/index.js"
></script>
<script type="module" src="/dist/main.js"></script>
<script>
const logEvents = (selector, eventType) => {
document.querySelector(selector).addEventListener(eventType, (ev) => {
console.log(ev);
});
};
</script>
</head>

<body>
<h1>Component demo</h1>
<main>
<vscode-demo>
<vscode-table resizable style="width: 200px">
<vscode-table-header>
<vscode-table-header-cell min-width="50" preferred-width="75%"
>Col 1</vscode-table-header-cell
>
<vscode-table-header-cell min-width="50"
>Col 2</vscode-table-header-cell
>
</vscode-table-header>
<vscode-table-body>
<vscode-table-row>
<vscode-table-cell>cell 1</vscode-table-cell>
<vscode-table-cell>cell 2</vscode-table-cell>
</vscode-table-row>
</vscode-table-body>
</vscode-table>
</vscode-demo>

<vscode-demo>
<vscode-table resizable style="width: 500px">
<vscode-table-header>
<vscode-table-header-cell min-width="100"
>Col 1</vscode-table-header-cell
>
<vscode-table-header-cell>Col 2</vscode-table-header-cell>
</vscode-table-header>
<vscode-table-body>
<vscode-table-row>
<vscode-table-cell>cell 1</vscode-table-cell>
<vscode-table-cell>cell 2</vscode-table-cell>
</vscode-table-row>
</vscode-table-body>
</vscode-table>
</vscode-demo>

<vscode-demo>
<vscode-table resizable style="width: 600px">
<vscode-table-header>
<vscode-table-header-cell min-width="100">
Col A
</vscode-table-header-cell>
<vscode-table-header-cell min-width="200">
Col B
</vscode-table-header-cell>
<vscode-table-header-cell> Col C </vscode-table-header-cell>
</vscode-table-header>
<vscode-table-body>
<vscode-table-row>
<vscode-table-cell>A</vscode-table-cell>
<vscode-table-cell>B</vscode-table-cell>
<vscode-table-cell>C</vscode-table-cell>
</vscode-table-row>
</vscode-table-body>
</vscode-table>
</vscode-demo>
</main>
</body>
</html>
2 changes: 1 addition & 1 deletion package.json
Original file line number Diff line number Diff line change
Expand Up @@ -33,7 +33,7 @@
"icons": "node scripts/generateIconList.js",
"vscode-data": "wireit",
"ncu": "ncu -u",
"prepare": "npx playwright install chromium --only-shell"
"prepare": "npx playwright install chromium"
},
"wireit": {
"analyze": {
Expand Down
2 changes: 1 addition & 1 deletion src/includes/VscElement.ts
Original file line number Diff line number Diff line change
Expand Up @@ -11,7 +11,7 @@ const warn = (message: string, componentInstance?: VscElement) => {
console.warn(`${prefix}${message}\n%o`, componentInstance);
} else {
// eslint-disable-next-line no-console
console.warn(`${message}\n%o`, componentInstance);
console.warn(`${prefix}${message}`);
}
};

Expand Down
30 changes: 17 additions & 13 deletions src/includes/test-helpers.ts
Original file line number Diff line number Diff line change
Expand Up @@ -85,26 +85,30 @@ export async function moveMouseOnElement(

/** A testing utility that drags an element with the mouse. */
export async function dragElement(
/** The element to drag */
el: Element,
/** The horizontal distance to drag in pixels */
deltaX = 0,
/** The vertical distance to drag in pixels */
deltaY = 0,
callbacks: {
afterMouseDown?: () => void | Promise<void>;
afterMouseMove?: () => void | Promise<void>;
} = {}
steps = 1,
position: 'left' | 'right' | 'center' = 'center'
): Promise<void> {
await moveMouseOnElement(el);
await sendMouse({type: 'down'});
const start = determineMousePosition(el, position, 0, 0);

await callbacks.afterMouseDown?.();
await sendMouse({
type: 'move',
position: [start.clickX, start.clickY],
});

const {clickX, clickY} = determineMousePosition(el, 'center', deltaX, deltaY);
await sendMouse({type: 'move', position: [clickX, clickY]});
await sendMouse({type: 'down'});

await callbacks.afterMouseMove?.();
for (let i = 1; i <= steps; i++) {
await sendMouse({
type: 'move',
position: [
Math.round(start.clickX + (deltaX * i) / steps),
Math.round(start.clickY + (deltaY * i) / steps),
],
});
}

await sendMouse({type: 'up'});
}
Expand Down
13 changes: 12 additions & 1 deletion src/vscode-table-body/vscode-table-body.ts
Original file line number Diff line number Diff line change
Expand Up @@ -14,13 +14,24 @@ export class VscodeTableBody extends VscElement {
@property({reflect: true})
override role = 'rowgroup';

private _handleSlotChange() {
/** @internal */
this.dispatchEvent(
new Event('vsc-table-body-slot-changed', {bubbles: true})
);
}

override render(): TemplateResult {
return html` <slot></slot> `;
return html` <slot @slotchange=${this._handleSlotChange}></slot> `;
}
}

declare global {
interface HTMLElementTagNameMap {
'vscode-table-body': VscodeTableBody;
}

interface GlobalEventHandlersEventMap {
'vsc-table-body-slot-changed': Event;
}
}
21 changes: 20 additions & 1 deletion src/vscode-table-header-cell/vscode-table-header-cell.ts
Original file line number Diff line number Diff line change
Expand Up @@ -8,6 +8,11 @@ export type VscTableChangeMinColumnWidthEvent = CustomEvent<{
propertyValue: string;
}>;

export type VscTableChangePreferredColumnWidthEvent = CustomEvent<{
columnIndex: number;
propertyValue: string;
}>;

/**
* @tag vscode-table-header-cell
*
Expand All @@ -20,7 +25,10 @@ export class VscodeTableHeaderCell extends VscElement {
static override styles = styles;

@property({attribute: 'min-width'})
minWidth = '0';
minWidth: string | undefined = undefined;

@property({attribute: 'preferred-width'})
preferredWidth = 'auto';

/** @internal */
@property({type: Number})
Expand All @@ -40,6 +48,16 @@ export class VscodeTableHeaderCell extends VscElement {
}) as VscTableChangeMinColumnWidthEvent
);
}

if (changedProperties.has('preferredWidth') && this.index > -1) {
/** @internal */
this.dispatchEvent(
new CustomEvent('vsc-table-change-preferred-column-width', {
detail: {columnIndex: this.index, propertyValue: this.preferredWidth},
bubbles: true,
}) as VscTableChangePreferredColumnWidthEvent
);
}
}

override render(): TemplateResult {
Expand All @@ -58,5 +76,6 @@ declare global {

interface GlobalEventHandlersEventMap {
'vsc-table-change-min-column-width': VscTableChangeMinColumnWidthEvent;
'vsc-table-change-preferred-column-width': VscTableChangePreferredColumnWidthEvent;
}
}
13 changes: 7 additions & 6 deletions src/vscode-table/calculations.ts
Original file line number Diff line number Diff line change
Expand Up @@ -37,14 +37,15 @@ export function calculateColumnWidths(
let totalAvailable: Percent = percent(0);

for (const i of shrinkingSide) {
const available = Math.max(0, result[i] - (minWidths.get(i) ?? 0));
const min = minWidths.get(i) ?? percent(0);
const available = Math.max(0, result[i] - min);
totalAvailable = percent(totalAvailable + available);
}

// Abort if the requested delta cannot be fully satisfied
if (totalAvailable < remaining) {
return result;
}
const effectiveDelta =
totalAvailable < remaining ? totalAvailable : remaining;

remaining = percent(effectiveDelta);

// Shrink columns sequentially until the delta is fully consumed
for (const i of shrinkingSide) {
Expand All @@ -60,7 +61,7 @@ export function calculateColumnWidths(
}

// Apply the exact opposite delta to the growing side
let toAdd: Percent = percent(absDelta);
let toAdd: Percent = percent(effectiveDelta);

for (const i of growingSide) {
if (toAdd === 0) {
Expand Down
61 changes: 61 additions & 0 deletions src/vscode-table/initial-column-widths.ts
Original file line number Diff line number Diff line change
@@ -0,0 +1,61 @@
import {percent, Percent} from '../includes/sizes.js';

const PERCENT_FULL = percent(100);

export type ColumnWidth = Percent | 'auto';

export interface Column {
preferredWidth: ColumnWidth;
minWidth: Percent;
}

export function calculateInitialWidths(columns: Column[]): Percent[] {
const finalWidths: Percent[] = columns.map(
(c) =>
typeof c.preferredWidth === 'number'
? percent(Math.max(c.preferredWidth, c.minWidth))
: percent(0) // auto placeholder
);

const autoIndices = columns
.map((c, i) => (c.preferredWidth === 'auto' ? i : -1))
.filter((i) => i >= 0);

const totalMinWidth = columns.reduce(
(sum, c) => percent(sum + c.minWidth),
percent(0)
);

if (totalMinWidth > PERCENT_FULL) {
const scale = PERCENT_FULL / totalMinWidth;
return columns.map((c) => percent(c.minWidth * scale));
}

const fixedWidthSum = finalWidths.reduce(
(sum, w) => percent(sum + w),
percent(0)
);
const remainingSpace = percent(PERCENT_FULL - fixedWidthSum);

if (remainingSpace > 0 && autoIndices.length > 0) {
const extraPerAuto = remainingSpace / autoIndices.length;
for (const i of autoIndices) {
finalWidths[i] = percent(Math.max(columns[i].minWidth, extraPerAuto));
}
return finalWidths;
}

if (autoIndices.length > 0) {
for (const i of autoIndices) {
finalWidths[i] = columns[i].minWidth;
}
return finalWidths;
}

if (remainingSpace > 0 && autoIndices.length === 0) {
const scale = PERCENT_FULL / fixedWidthSum;
return finalWidths.map((w) => percent(w * scale));
}

return finalWidths;
}
Loading