diff --git a/packages/uui-boolean-input/lib/uui-boolean-input.element.ts b/packages/uui-boolean-input/lib/uui-boolean-input.element.ts
index fd1ce1eaa..86000050a 100644
--- a/packages/uui-boolean-input/lib/uui-boolean-input.element.ts
+++ b/packages/uui-boolean-input/lib/uui-boolean-input.element.ts
@@ -114,14 +114,14 @@ export abstract class UUIBooleanInputElement extends UUIFormControlMixin(
this._value = 'on';
}
this.inputRole = inputRole;
- this.addEventListener('keypress', this._onKeypress);
+ this.addEventListener('keydown', this.#onKeyDown);
}
protected getFormElement(): HTMLInputElement {
return this._input;
}
- private _onKeypress(e: KeyboardEvent): void {
+ #onKeyDown(e: KeyboardEvent): void {
if (e.key == 'Enter') {
this.submit();
}
diff --git a/packages/uui-boolean-input/lib/uui-boolean-input.test.ts b/packages/uui-boolean-input/lib/uui-boolean-input.test.ts
index 2a81274e7..45935baa9 100644
--- a/packages/uui-boolean-input/lib/uui-boolean-input.test.ts
+++ b/packages/uui-boolean-input/lib/uui-boolean-input.test.ts
@@ -128,8 +128,8 @@ describe('BooleanInputBaseElement in a Form', () => {
describe('submit', () => {
it('should submit when pressing enter', async () => {
- const listener = oneEvent(formElement, 'submit', false);
- element.dispatchEvent(new KeyboardEvent('keypress', { key: 'Enter' }));
+ const listener = oneEvent(formElement, 'submit');
+ element.dispatchEvent(new KeyboardEvent('keydown', { key: 'Enter' }));
const event = await listener;
expect(event).to.exist;
diff --git a/packages/uui-card-content-node/lib/uui-card-content-node.element.ts b/packages/uui-card-content-node/lib/uui-card-content-node.element.ts
index e0bc56d86..80658db04 100644
--- a/packages/uui-card-content-node/lib/uui-card-content-node.element.ts
+++ b/packages/uui-card-content-node/lib/uui-card-content-node.element.ts
@@ -24,11 +24,30 @@ export class UUICardContentNodeElement extends UUICardElement {
@property({ type: String })
name = '';
+ /**
+ * Node details
+ * @type {string}
+ * @attr
+ * @default ''
+ */
+ @property({ type: String })
+ detail = '';
+
@state()
private _iconSlotHasContent = false;
- protected fallbackIcon =
- '';
+ protected fallbackIcon = ``;
private _onSlotIconChange(event: Event) {
this._iconSlotHasContent =
@@ -41,18 +60,37 @@ export class UUICardContentNodeElement extends UUICardElement {
return html``;
}
+ protected renderDetail() {
+ return html`${this.detail}`;
+ }
+
+ #renderContent() {
+ return html`
+
+
+
+
+ ${this._iconSlotHasContent === false
+ ? this._renderFallbackIcon()
+ : ''}
+
+ ${this.name}
+
+ ${this.renderDetail()}
+
+ `;
+ }
+
#renderButton() {
- return html`
${stepValues.map(value => html`
${value}`)}
diff --git a/packages/uui-range-slider/lib/uui-range-slider.test.ts b/packages/uui-range-slider/lib/uui-range-slider.test.ts
index c4a6cf2cc..d9185e0a7 100644
--- a/packages/uui-range-slider/lib/uui-range-slider.test.ts
+++ b/packages/uui-range-slider/lib/uui-range-slider.test.ts
@@ -78,7 +78,7 @@ describe('UUIRangeSliderElement', () => {
describe('events', () => {
describe('change', () => {
it('emits a change event from inputLow when native input fires one', async () => {
- const listener = oneEvent(element, UUIRangeSliderEvent.CHANGE, false);
+ const listener = oneEvent(element, UUIRangeSliderEvent.CHANGE);
inputLow.dispatchEvent(new Event('change'));
const event = await listener;
expect(event).to.exist;
@@ -86,7 +86,7 @@ describe('UUIRangeSliderElement', () => {
expect(event!.target).to.equal(element);
});
it('emits a change event from inputHigh when native input fires one', async () => {
- const listener = oneEvent(element, UUIRangeSliderEvent.CHANGE, false);
+ const listener = oneEvent(element, UUIRangeSliderEvent.CHANGE);
inputHigh.dispatchEvent(new Event('change'));
const event = await listener;
expect(event).to.exist;
@@ -96,7 +96,7 @@ describe('UUIRangeSliderElement', () => {
});
describe('input', () => {
it('emits an input event from inputLow when native input fires one', async () => {
- const listener = oneEvent(element, UUIRangeSliderEvent.INPUT, false);
+ const listener = oneEvent(element, UUIRangeSliderEvent.INPUT);
inputLow.dispatchEvent(new Event('input'));
const event = await listener;
expect(event).to.exist;
@@ -104,7 +104,7 @@ describe('UUIRangeSliderElement', () => {
expect(event!.target).to.equal(element);
});
it('emits an input event from inputHigh when native input fires one', async () => {
- const listener = oneEvent(element, UUIRangeSliderEvent.INPUT, false);
+ const listener = oneEvent(element, UUIRangeSliderEvent.INPUT);
inputHigh.dispatchEvent(new Event('input'));
const event = await listener;
expect(event).to.exist;
@@ -164,8 +164,8 @@ describe('UUIRangeSlider in a form', () => {
describe('submit', () => {
it('should submit when pressing enter', async () => {
- const listener = oneEvent(formElement, 'submit', false);
- element.dispatchEvent(new KeyboardEvent('keypress', { key: 'Enter' }));
+ const listener = oneEvent(formElement, 'submit');
+ element.dispatchEvent(new KeyboardEvent('keydown', { key: 'Enter' }));
const event = await listener;
expect(event).to.exist;
diff --git a/packages/uui-ref-node/lib/uui-ref-node.element.ts b/packages/uui-ref-node/lib/uui-ref-node.element.ts
index 2ae97da50..f8e12b8f5 100644
--- a/packages/uui-ref-node/lib/uui-ref-node.element.ts
+++ b/packages/uui-ref-node/lib/uui-ref-node.element.ts
@@ -67,8 +67,18 @@ export class UUIRefNodeElement extends UUIRefElement {
@state()
private _iconSlotHasContent = false;
- protected fallbackIcon =
- '
';
+ protected fallbackIcon = `
`;
connectedCallback() {
super.connectedCallback();
@@ -141,17 +151,17 @@ export class UUIRefNodeElement extends UUIRefElement {
public render() {
return html`
- ${this.#renderSomething()}
+ ${this.#renderOpenPart()}
-
+
`;
}
- #renderSomething() {
+ #renderOpenPart() {
if (this.readonly) {
return html`${this.#renderContent()}`;
} else {
@@ -164,7 +174,7 @@ export class UUIRefNodeElement extends UUIRefElement {
css`
:host {
min-width: 250px;
- padding: calc(var(--uui-size-2) + 1px);
+ padding: 1px;
}
#content {
@@ -179,6 +189,10 @@ export class UUIRefNodeElement extends UUIRefElement {
color: inherit;
text-decoration: none;
cursor: pointer;
+ align-self: stretch;
+ display: flex;
+ flex-grow: 1;
+ padding: calc(var(--uui-size-2));
}
#icon {
@@ -204,11 +218,16 @@ export class UUIRefNodeElement extends UUIRefElement {
font-size: var(--uui-type-small-size);
}
+ :host([selectable]) #open-part {
+ flex-grow: 0;
+ padding: 0;
+ margin: calc(var(--uui-size-2));
+ }
+
:host(:not([disabled])) #open-part:hover #icon {
color: var(--uui-color-interactive-emphasis);
}
:host(:not([disabled])) #open-part:hover #name {
- font-weight: 700;
text-decoration: underline;
color: var(--uui-color-interactive-emphasis);
}
diff --git a/packages/uui-ref/lib/uui-ref.element.ts b/packages/uui-ref/lib/uui-ref.element.ts
index 63fada255..3b4782ce1 100644
--- a/packages/uui-ref/lib/uui-ref.element.ts
+++ b/packages/uui-ref/lib/uui-ref.element.ts
@@ -77,9 +77,11 @@ export class UUIRefElement extends SelectOnlyMixin(
transition: --uui-card-before-opacity 120ms;
}
- :host(:focus) {
- /** TODO: implement focus outline. */
- outline-color: #6ab4f0;
+ :host([selectable]:focus-visible) {
+ outline-color: var(--uui-color-focus);
+ outline-width: var(--uui-card-border-width);
+ outline-style: solid;
+ outline-offset: var(--uui-card-border-width);
}
:host([error]) {
@@ -179,6 +181,19 @@ export class UUIRefElement extends SelectOnlyMixin(
text-align: left;
color: var(--uui-color-text);
}
+ a {
+ text-decoration: none;
+ color: inherit;
+ }
+
+ button:focus,
+ a:focus {
+ outline-color: var(--uui-color-focus);
+ outline-width: var(--uui-card-border-width);
+ outline-style: solid;
+ outline-offset: var(--uui-card-border-width);
+ border-radius: var(--uui-border-radius);
+ }
slot[name='actions'] {
display: flex;
@@ -186,11 +201,16 @@ export class UUIRefElement extends SelectOnlyMixin(
--uui-button-height: calc(var(--uui-size-2) * 4);
margin-right: var(--uui-size-2);
}
+ #tag-container {
+ margin: calc(var(--uui-size-2));
+ }
#actions-container {
+ margin: calc(var(--uui-size-2));
opacity: 0;
transition: opacity 120ms;
}
:host(:hover) #actions-container,
+ :host(:focus) #actions-container,
:host(:focus-within) #actions-container {
opacity: 1;
}
@@ -208,8 +228,6 @@ export class UUIRefElement extends SelectOnlyMixin(
}
slot[name='tag'] {
- flex-grow: 1;
-
display: flex;
justify-content: flex-end;
align-items: center;
diff --git a/packages/uui-slider/lib/uui-slider.element.ts b/packages/uui-slider/lib/uui-slider.element.ts
index dd1f750a9..612c22ec7 100644
--- a/packages/uui-slider/lib/uui-slider.element.ts
+++ b/packages/uui-slider/lib/uui-slider.element.ts
@@ -11,42 +11,14 @@ import { UUISliderEvent } from './UUISliderEvent';
const TRACK_PADDING = 12;
const STEP_MIN_WIDTH = 24;
-const RenderTrackSteps = (steps: number[], stepWidth: number) => {
- return svg`
- ${steps.map(el => {
- if (stepWidth >= STEP_MIN_WIDTH) {
- const x = Math.round(TRACK_PADDING + stepWidth * steps.indexOf(el));
- return svg`
`;
- }
- return svg``;
- })}
-`;
-};
-
-const RenderStepValues = (
- steps: number[],
- stepWidth: number,
- hide: boolean,
-) => {
- if (hide) return nothing;
-
- return html`
- ${steps.map(
- el =>
- html`
- ${steps.length <= 20 && stepWidth >= STEP_MIN_WIDTH
- ? el.toFixed(0)
- : nothing}
- `,
- )}
-
`;
-};
-
const GenerateStepArray = (start: number, stop: number, step: number) =>
Array.from({ length: (stop - start) / step + 1 }, (_, i) => start + i * step);
+const CountDecimalPlaces = (num: number) => {
+ const decimalIndex = num.toString().indexOf('.');
+ return decimalIndex >= 0 ? num.toString().length - decimalIndex - 1 : 0;
+};
+
/**
* @element uui-slider
* @description - Native `
` wrapper.
@@ -188,7 +160,7 @@ export class UUISliderElement extends UUIFormControlMixin(LitElement, '') {
this.addEventListener('blur', () => {
this.style.setProperty('--uui-show-focus-outline', '');
});
- this.addEventListener('keypress', this._onKeypress);
+ this.addEventListener('keydown', this.#onKeyDown);
}
/**
@@ -264,7 +236,7 @@ export class UUISliderElement extends UUIFormControlMixin(LitElement, '') {
this._stepWidth = this._calculateStepWidth();
};
- private _onKeypress(e: KeyboardEvent): void {
+ #onKeyDown(e: KeyboardEvent): void {
if (e.key == 'Enter') {
this.submit();
}
@@ -295,6 +267,37 @@ export class UUISliderElement extends UUIFormControlMixin(LitElement, '') {
this.dispatchEvent(new UUISliderEvent(UUISliderEvent.CHANGE));
}
+ renderTrackSteps() {
+ return svg`
+ ${this._steps.map(el => {
+ if (this._stepWidth >= STEP_MIN_WIDTH) {
+ const x = Math.round(
+ TRACK_PADDING + this._stepWidth * this._steps.indexOf(el),
+ );
+ return svg`
`;
+ }
+ return svg``;
+ })}
+`;
+ }
+
+ renderStepValues() {
+ if (this.hideStepValues) return nothing;
+
+ return html`
+ ${this._steps.map(
+ el =>
+ html`
+ ${this._steps.length <= 20 && this._stepWidth >= STEP_MIN_WIDTH
+ ? el.toFixed(CountDecimalPlaces(this.step))
+ : nothing}
+ `,
+ )}
+
`;
+ }
+
render() {
return html`
@@ -323,7 +326,7 @@ export class UUISliderElement extends UUIFormControlMixin(LitElement, '') {
- ${RenderStepValues(this._steps, this._stepWidth, this.hideStepValues)}
+ ${this.renderStepValues()}
`;
}
diff --git a/packages/uui-slider/lib/uui-slider.story.ts b/packages/uui-slider/lib/uui-slider.story.ts
index af730a803..95288bb2f 100644
--- a/packages/uui-slider/lib/uui-slider.story.ts
+++ b/packages/uui-slider/lib/uui-slider.story.ts
@@ -56,3 +56,12 @@ export const Readonly: Story = {
readonly: true,
},
};
+
+export const DecimalValue: Story = {
+ args: {
+ min: 0,
+ max: 1,
+ step: 0.1,
+ value: 0.5,
+ },
+};
diff --git a/packages/uui-slider/lib/uui-slider.test.ts b/packages/uui-slider/lib/uui-slider.test.ts
index 5fd59efa2..cf52c58bc 100644
--- a/packages/uui-slider/lib/uui-slider.test.ts
+++ b/packages/uui-slider/lib/uui-slider.test.ts
@@ -73,7 +73,7 @@ describe('UuiSlider', () => {
describe('events', () => {
describe('change', () => {
it('emits a change event when native input fires one', async () => {
- const listener = oneEvent(element, UUISliderEvent.CHANGE, false);
+ const listener = oneEvent(element, UUISliderEvent.CHANGE);
input.dispatchEvent(new Event('change'));
@@ -85,7 +85,7 @@ describe('UuiSlider', () => {
});
describe('input', () => {
it('emits a input event when native input fires one', async () => {
- const listener = oneEvent(element, UUISliderEvent.INPUT, false);
+ const listener = oneEvent(element, UUISliderEvent.INPUT);
input.dispatchEvent(new Event('input'));
@@ -150,8 +150,8 @@ describe('UuiSlider in Form', () => {
describe('submit', () => {
it('should submit when pressing enter', async () => {
- const listener = oneEvent(formElement, 'submit', false);
- element.dispatchEvent(new KeyboardEvent('keypress', { key: 'Enter' }));
+ const listener = oneEvent(formElement, 'submit');
+ element.dispatchEvent(new KeyboardEvent('keydown', { key: 'Enter' }));
const event = await listener;
expect(event).to.exist;
diff --git a/packages/uui-symbol-file/lib/uui-symbol-file.element.ts b/packages/uui-symbol-file/lib/uui-symbol-file.element.ts
index c949b300d..9db4512c1 100644
--- a/packages/uui-symbol-file/lib/uui-symbol-file.element.ts
+++ b/packages/uui-symbol-file/lib/uui-symbol-file.element.ts
@@ -1,6 +1,7 @@
import { LitElement, html, css } from 'lit';
import { defineElement } from '@umbraco-ui/uui-base/lib/registration';
import { property } from 'lit/decorators.js';
+import { UUITextStyles } from '@umbraco-ui/uui-css/lib';
/**
* @element uui-file-symbol
@@ -16,20 +17,30 @@ export class UUISymbolFileElement extends LitElement {
type = '';
render() {
- return html`