Skip to content
Merged
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
4 changes: 2 additions & 2 deletions projects/core/.visual/pagination.dark.png
Loading
Sorry, something went wrong. Reload?
Sorry, we cannot display this file.
Sorry, this file is invalid so it cannot be displayed.
4 changes: 2 additions & 2 deletions projects/core/.visual/pagination.png
Loading
Sorry, something went wrong. Reload?
Sorry, we cannot display this file.
Sorry, this file is invalid so it cannot be displayed.
4 changes: 2 additions & 2 deletions projects/core/.visual/select.dark.png
Loading
Sorry, something went wrong. Reload?
Sorry, we cannot display this file.
Sorry, this file is invalid so it cannot be displayed.
4 changes: 2 additions & 2 deletions projects/core/.visual/select.png
Loading
Sorry, something went wrong. Reload?
Sorry, we cannot display this file.
Sorry, this file is invalid so it cannot be displayed.
4 changes: 2 additions & 2 deletions projects/core/.visual/toolbar.dark.png
Loading
Sorry, something went wrong. Reload?
Sorry, we cannot display this file.
Sorry, this file is invalid so it cannot be displayed.
4 changes: 2 additions & 2 deletions projects/core/.visual/toolbar.png
Loading
Sorry, something went wrong. Reload?
Sorry, we cannot display this file.
Sorry, this file is invalid so it cannot be displayed.
10 changes: 10 additions & 0 deletions projects/core/src/forms/control/control.css
Original file line number Diff line number Diff line change
Expand Up @@ -53,6 +53,16 @@
--width: fit-content;
}

:host([fit-text]) {
--max-width: fit-content;
--width: fit-content;

::slotted(input),
::slotted(select) {
field-sizing: content;
}
}

:host([nve-control]) ::slotted(input:focus),
:host([nve-control]) ::slotted(select:focus),
:host([nve-control]) ::slotted(textarea:focus),
Expand Down
85 changes: 48 additions & 37 deletions projects/core/src/forms/control/control.test.ts
Original file line number Diff line number Diff line change
Expand Up @@ -269,94 +269,105 @@ describe(`${Control.metadata.tag}: fit-text input`, () => {
removeFixture(fixture);
});

it('should set control width to input text character width', async () => {
it('should set input width to text content width', async () => {
await new Promise(resolve => requestAnimationFrame(resolve));
const fitTextWidth = input.getBoundingClientRect().width;

element.fitText = false;
await elementIsStable(element);
expect(element.style.getPropertyValue('--control-width')).toBe(`4ch`);
await new Promise(resolve => requestAnimationFrame(resolve));

expect(fitTextWidth).toBeLessThan(input.getBoundingClientRect().width);
});

it('should update control width to input text character width', async () => {
await elementIsStable(element);
it('should update input width to text content width', async () => {
await new Promise(resolve => requestAnimationFrame(resolve));
const initialWidth = input.getBoundingClientRect().width;

input.value = '123456789012345678901234567890';
input.dispatchEvent(new Event('input'));
await elementIsStable(element);
expect(element.style.getPropertyValue('--control-width')).toBe(`30ch`);
await new Promise(resolve => requestAnimationFrame(resolve));

expect(input.getBoundingClientRect().width).toBeGreaterThan(initialWidth);
});

it('should update control width to input text character width with icon offset', async () => {
await elementIsStable(element);
it('should update input width to native date content width', async () => {
await new Promise(resolve => requestAnimationFrame(resolve));
const textWidth = input.getBoundingClientRect().width;

input.type = 'date';
input.value = '';
input.dispatchEvent(new Event('input'));
await elementIsStable(element);
expect(element.style.getPropertyValue('--control-width')).toBe(`4ch`);
expect(input.style.maxWidth).toBe(`2ch`);
await new Promise(resolve => requestAnimationFrame(resolve));

expect(input.getBoundingClientRect().width).toBeGreaterThan(textWidth);
Comment thread
coderabbitai[bot] marked this conversation as resolved.
});
});

describe(`${Control.metadata.tag}: fit-content input`, () => {
describe(`${Control.metadata.tag}: fit-text select`, () => {
let fixture: HTMLElement;
let element: Control;
let input: HTMLInputElement;
let select: HTMLSelectElement;

beforeEach(async () => {
fixture = await createFixture(html`
<nve-control fit-content>
<nve-control fit-text>
<label>label</label>
<input type="text" />
<select>
<option value="short">Short</option>
<option value="long">A much longer option</option>
</select>
</nve-control>
`);
element = fixture.querySelector(Control.metadata.tag);
input = fixture.querySelector('input');
select = fixture.querySelector('select');
await elementIsStable(element);
});

afterEach(() => {
removeFixture(fixture);
});

it('should update control width to input browser default content', async () => {
it('should update select width to selected content width', async () => {
await new Promise(resolve => requestAnimationFrame(resolve));
const initialWidth = select.getBoundingClientRect().width;

select.value = 'long';
select.dispatchEvent(new Event('change'));
await elementIsStable(element);
await new Promise(r => requestAnimationFrame(r));
expect(Math.floor(input.getBoundingClientRect().width) > 100).toBe(true);
expect(Math.floor(input.getBoundingClientRect().width) < 250).toBe(true);
await new Promise(resolve => requestAnimationFrame(resolve));

expect(select.getBoundingClientRect().width).toBeGreaterThan(initialWidth);
});
});

describe(`${Control.metadata.tag}: fit-text select`, () => {
describe(`${Control.metadata.tag}: fit-content input`, () => {
let fixture: HTMLElement;
let element: Control;
let input: HTMLSelectElement;
let input: HTMLInputElement;

beforeEach(async () => {
fixture = await createFixture(html`
<nve-control fit-text>
<nve-control fit-content>
<label>label</label>
<select>
<option value="1">Option 1</option>
<option value="2">Option 12345678</option>
</select>
<nve-control-message>message</nve-control-message>
<input type="text" />
</nve-control>
`);
element = fixture.querySelector(Control.metadata.tag);
input = fixture.querySelector('select');
input = fixture.querySelector('input');
await elementIsStable(element);
});

afterEach(() => {
removeFixture(fixture);
});

it('should set control width to input text character width', async () => {
await elementIsStable(element);
expect(element.style.getPropertyValue('--control-width')).toBe(`12ch`);
});

it('should update control width to input text character width', async () => {
await elementIsStable(element);
input.value = '2';
input.dispatchEvent(new Event('change'));
it('should update control width to input browser default content', async () => {
await elementIsStable(element);
expect(element.style.getPropertyValue('--control-width')).toBe(`19ch`);
await new Promise(r => requestAnimationFrame(r));
expect(Math.floor(input.getBoundingClientRect().width) > 100).toBe(true);
expect(Math.floor(input.getBoundingClientRect().width) < 250).toBe(true);
});
});
30 changes: 0 additions & 30 deletions projects/core/src/forms/control/control.ts
Original file line number Diff line number Diff line change
Expand Up @@ -171,10 +171,6 @@ export class Control extends LitElement {
super.disconnectedCallback();
this.shadowRoot!.removeEventListener('slotchange', this.#onRootSlotchange);
this.shadowRoot!.removeEventListener('slotchange', this.#onInputSlotchange);
if (this.fitText && this.input) {
this.input.removeEventListener('input', this.#onFitTextUpdate);
this.input.removeEventListener('change', this.#onFitTextUpdate);
}
this.#observers.forEach(observer => observer.disconnect());
this.#observers.length = 0;
}
Expand All @@ -184,7 +180,6 @@ export class Control extends LitElement {

if (this.input && this.#observers.length === 0) {
this.#setupInput();
this.#setupFitText();
}
};

Expand Down Expand Up @@ -242,31 +237,6 @@ export class Control extends LitElement {
this.#updateAssociations();
};

#setupFitText() {
if (this.fitText) {
this.#getCharacterWidth();
this.input.addEventListener('input', this.#onFitTextUpdate);
this.input.addEventListener('change', this.#onFitTextUpdate);
}
}

#onFitTextUpdate = () => {
this.#getCharacterWidth();
};

#getCharacterWidth() {
if (this.input.tagName === 'INPUT') {
const offset = this.input.type !== 'text' ? 4 : 0;
this.style.setProperty('--control-width', `${this.input.value.length + offset}ch`);
this.input.style.setProperty('max-width', `${this.input.value.length + 2}ch`, 'important');
} else if (this.input.tagName === 'SELECT') {
this.style.setProperty(
'--control-width',
`${(this.input as unknown as HTMLSelectElement).options[(this.input as unknown as HTMLSelectElement).selectedIndex]!.textContent!.length + 4}ch`
);
}
}

#polyfillShowPicker() {
if (!this.input.showPicker) {
this.input.showPicker = () => this.input.focus();
Expand Down
4 changes: 0 additions & 4 deletions projects/core/src/input/input.css
Original file line number Diff line number Diff line change
Expand Up @@ -22,10 +22,6 @@
min-width: var(--min-width);
}

:host([fit-text]) {
--max-width: fit-content;
}

[input] {
height: var(--height);
background: var(--background);
Expand Down
8 changes: 6 additions & 2 deletions projects/core/src/select/select.css
Original file line number Diff line number Diff line change
Expand Up @@ -23,8 +23,7 @@
--_icon-color: var(--color);
--_gap: var(--gap);
--size: 1;
--_row-height: calc(var(--height) * var(--size) + var(--gap) * (var(--size) - 1));
--_height: calc(var(--_row-height) + var(--nve-ref-border-width-md) * 2);
--_height: var(--height);
Comment thread
coryrylan marked this conversation as resolved.
contain: initial;
width: var(--width);
max-width: var(--max-width);
Expand Down Expand Up @@ -139,6 +138,11 @@
opacity: 0 !important;
}

:host(:state(size)) {
--_row-height: calc(var(--height) * var(--size) + var(--gap) * (var(--size) - 1));
--_height: calc(var(--_row-height) + var(--nve-ref-border-width-md) * 2);
}

:host(:state(size)) [input] {
overflow: auto;
display: block;
Expand Down