Skip to content

Commit 975a57d

Browse files
authored
Merge pull request #135 from umbraco/feature/uui-form-item
UUI-Form-item
2 parents 9fbba96 + 5329cfd commit 975a57d

26 files changed

+812
-11
lines changed

.gitignore

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -34,6 +34,7 @@ out-css
3434
*.log
3535
.eslintcache
3636
*.tgz
37+
.turbo
3738

3839
# old source
3940
/src

package-lock.json

Lines changed: 43 additions & 0 deletions
Some generated files are not rendered by default. Learn more about customizing how changed files appear on GitHub.
Lines changed: 17 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,17 @@
1+
import { FormControlMixinInterface } from '../mixins';
2+
import { UUIEvent } from './UUIEvent';
3+
4+
export class UUIFormControlEvent extends UUIEvent<
5+
{},
6+
FormControlMixinInterface
7+
> {
8+
constructor(evName: string, eventInit: any | null = {}) {
9+
super(evName, {
10+
...{ bubbles: true },
11+
...eventInit,
12+
});
13+
}
14+
15+
public static readonly VALID = 'valid';
16+
public static readonly INVALID = 'invalid';
17+
}

packages/uui-base/lib/events/index.ts

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -1,2 +1,3 @@
11
export * from './UUIEvent';
2+
export * from './UUIFormControlEvent';
23
export * from './UUISelectableEvent';

packages/uui-base/lib/mixins/FormControlMixin.ts

Lines changed: 22 additions & 4 deletions
Original file line numberDiff line numberDiff line change
@@ -1,16 +1,18 @@
11
import { LitElement } from 'lit';
22
import { property } from 'lit/decorators.js';
3+
import { UUIFormControlEvent } from '../events';
34

45
type Constructor<T = {}> = new (...args: any[]) => T;
56

6-
// TODO: make t possible to define FormDataEntryValue type.
7-
export declare abstract class FormControlMixinInterface {
7+
// TODO: make it possible to define FormDataEntryValue type.
8+
export declare abstract class FormControlMixinInterface extends LitElement {
89
formAssociated: boolean;
910
get value(): FormDataEntryValue;
1011
set value(newValue: FormDataEntryValue);
1112
name: string;
1213
formResetCallback(): void;
13-
checkValidity: Function;
14+
checkValidity: () => boolean;
15+
get validationMessage(): string;
1416
protected _value: FormDataEntryValue;
1517
protected _internals: any;
1618
protected abstract getFormElement(): HTMLElement | undefined;
@@ -204,14 +206,26 @@ export const FormControlMixin = <T extends Constructor<LitElement>>(
204206

205207
const hasError = Object.values(this._validityState).includes(true);
206208

207-
if (hasError === false) {
209+
if (hasError) {
210+
this.dispatchEvent(
211+
new UUIFormControlEvent(UUIFormControlEvent.INVALID)
212+
);
213+
} else {
208214
this._internals.setValidity({});
215+
this.dispatchEvent(new UUIFormControlEvent(UUIFormControlEvent.VALID));
209216
}
210217
}
211218

212219
updated(changedProperties: Map<string | number | symbol, unknown>) {
213220
super.updated(changedProperties);
214221
this._runValidators();
222+
/*
223+
if(changedProperties.has('pristine')) {
224+
if(changedProperties.get('pristine') === false) {
225+
this._internals.reportValidity();
226+
}
227+
}
228+
*/
215229
}
216230

217231
private _onFormSubmit = () => {
@@ -237,6 +251,10 @@ export const FormControlMixin = <T extends Constructor<LitElement>>(
237251
public checkValidity() {
238252
return this._internals?.checkValidity();
239253
}
254+
255+
get validationMessage() {
256+
return this._internals?.validationMessage;
257+
}
240258
}
241259
return FormControlMixinClass as unknown as Constructor<FormControlMixinInterface> &
242260
T;

packages/uui-boolean-input/lib/uui-boolean-input.element.ts

Lines changed: 5 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -148,7 +148,11 @@ export abstract class UUIBooleanInputElement extends FormControlMixin(
148148
this.checked = this.hasAttribute('checked');
149149
}
150150

151-
protected firstUpdated(): void {
151+
protected firstUpdated(
152+
_changedProperties: Map<string | number | symbol, unknown>
153+
): void {
154+
super.firstUpdated(_changedProperties);
155+
152156
const labelEl = this.shadowRoot?.querySelector('label') as HTMLLabelElement;
153157

154158
// hide outline if mouse-interaction:

packages/uui-css/lib/custom-properties/colors.css

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -166,6 +166,7 @@
166166
--uui-color-grey-dark: color($grey blackness(+ 10%));
167167
--uui-color-grey-dimmed: color($grey saturation(- 100%) blackness(+ 4%));
168168

169+
/** not begin used currently. */
169170
$dusty-grey: #9b9b9b;
170171
--uui-color-dusty-grey: $dusty-grey;
171172
--uui-color-dusty-grey-light: color($dusty-grey lightness(+ 8%));
Lines changed: 31 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,31 @@
1+
# uui-form-layout-item
2+
3+
![npm](https://img.shields.io/npm/v/@umbraco-ui/uui-form-layout-item?logoColor=%231B264F)
4+
5+
Umbraco style uui-form-layout-item component.
6+
7+
## Installation
8+
9+
### ES imports
10+
11+
```zsh
12+
npm i @umbraco-ui/uui-form-layout-item
13+
```
14+
15+
Import the registration of `<uui-form-layout-item>` via:
16+
17+
```javascript
18+
import '@umbraco-ui/uui-form-layout-item/';
19+
```
20+
21+
When looking to leverage the `UUIFormLayoutItemElement` base class as a type and/or for extension purposes, do so via:
22+
23+
```javascript
24+
import { UUIFormLayoutItemElement } from '@umbraco-ui/uui-form-layout-item';
25+
```
26+
27+
## Usage
28+
29+
```html
30+
<uui-form-layout-item></uui-form-layout-item>
31+
```
Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1 @@
1+
export * from './uui-form-layout-item.element';
Lines changed: 89 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,89 @@
1+
import { LitElement, html, css } from 'lit';
2+
import { property, state } from 'lit/decorators.js';
3+
import { defineElement } from '@umbraco-ui/uui-base/lib/registration';
4+
5+
// TODO: Make sure validation messages can be seen for the whole Form Item. Make them follow the screen if form controls are taller than available screen height.
6+
7+
/**
8+
* @element uui-form-layout-item
9+
* @description - Form item composes label, input and validation-messages in a proper layout.
10+
* @slot - for button contents
11+
* @slot message - for extras in the messages container
12+
*/
13+
14+
@defineElement('uui-form-layout-item')
15+
export class UUIFormLayoutItemElement extends LitElement {
16+
static styles = [
17+
css`
18+
:host {
19+
position: relative;
20+
display: block;
21+
margin-top: var(--uui-size-space-5);
22+
margin-bottom: var(--uui-size-space-5);
23+
}
24+
#label {
25+
margin-top: -5px;
26+
margin-bottom: 5px;
27+
}
28+
#description {
29+
color: var(--uui-interface-contrast-disabled);
30+
font-size: var(--uui-type-small-size);
31+
}
32+
#label + #description {
33+
margin-top: -8px;
34+
min-height: 8px;
35+
}
36+
`,
37+
];
38+
/*
39+
@property({type: String})
40+
label: string | null = null;
41+
*/
42+
43+
@property({ type: String })
44+
description: string | null = null;
45+
46+
@state()
47+
private _labelSlotHasContent = false;
48+
49+
private _labelSlotChanged = (e: Event) => {
50+
this._labelSlotHasContent =
51+
(e.target as HTMLSlotElement).assignedNodes({ flatten: true }).length > 0;
52+
};
53+
54+
@state()
55+
private _descriptionSlotHasContent = false;
56+
57+
private _descriptionSlotChanged = (e: Event) => {
58+
this._descriptionSlotHasContent =
59+
(e.target as HTMLSlotElement).assignedNodes({ flatten: true }).length > 0;
60+
};
61+
62+
render() {
63+
return html`
64+
<div id="label" style=${this._labelSlotHasContent ? '' : 'display: none'}>
65+
<slot name="label" @slotchange=${this._labelSlotChanged}></slot>
66+
</div>
67+
<div
68+
id="description"
69+
style=${this._descriptionSlotHasContent || this.description !== null
70+
? ''
71+
: 'display: none'}>
72+
${this.description}
73+
<slot
74+
name="description"
75+
@slotchange=${this._descriptionSlotChanged}></slot>
76+
</div>
77+
<uui-form-validation-message>
78+
<slot></slot>
79+
<slot name="message" slot="message"></slot>
80+
</uui-form-validation-message>
81+
`;
82+
}
83+
}
84+
85+
declare global {
86+
interface HTMLElementTagNameMap {
87+
'uui-form-layout-item': UUIFormLayoutItemElement;
88+
}
89+
}

0 commit comments

Comments
 (0)