@umbraco-ui/uui 2.0.0-rc.1 → 2.0.0-rc.2
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- package/custom-elements.json +38 -2
- package/dist/components/breadcrumbs/breadcrumb-item.element.d.ts +1 -0
- package/dist/components/breadcrumbs/breadcrumb-item.element.js +22 -5
- package/dist/components/breadcrumbs/breadcrumb-item.element.js.map +1 -1
- package/dist/components/input/input.element.js +2 -2
- package/dist/components/input/input.element.js.map +1 -1
- package/dist/components/pagination/pagination.element.js +1 -0
- package/dist/components/pagination/pagination.element.js.map +1 -1
- package/dist/components/popover-container/popover-container-nestedslottester.element.d.ts +26 -0
- package/dist/components/popover-container/popover-container.element.d.ts +1 -0
- package/dist/components/popover-container/popover-container.element.js +30 -6
- package/dist/components/popover-container/popover-container.element.js.map +1 -1
- package/dist/components/table/table-row.element.js +2 -2
- package/dist/components/table/table-row.element.js.map +1 -1
- package/dist/components/table/table.element.js +1 -1
- package/dist/components/table/table.element.js.map +1 -1
- package/dist/components/tabs/tab-group.element.js +17 -1
- package/dist/components/tabs/tab-group.element.js.map +1 -1
- package/dist/components/tabs/tab.element.js +3 -3
- package/dist/components/tabs/tab.element.js.map +1 -1
- package/dist/package.json.js +1 -1
- package/package.json +10 -10
- package/vscode.html-custom-data.json +326 -533
package/custom-elements.json
CHANGED
|
@@ -3002,7 +3002,7 @@
|
|
|
3002
3002
|
{
|
|
3003
3003
|
"name": "selectable",
|
|
3004
3004
|
"description": "Enable the ability to select this element.",
|
|
3005
|
-
"type": "
|
|
3005
|
+
"type": "Symbol()",
|
|
3006
3006
|
"default": "true"
|
|
3007
3007
|
},
|
|
3008
3008
|
{
|
|
@@ -3055,7 +3055,7 @@
|
|
|
3055
3055
|
"name": "selectable",
|
|
3056
3056
|
"attribute": "selectable",
|
|
3057
3057
|
"description": "Enable the ability to select this element.",
|
|
3058
|
-
"type": "
|
|
3058
|
+
"type": "Symbol()",
|
|
3059
3059
|
"default": "true"
|
|
3060
3060
|
},
|
|
3061
3061
|
{
|
|
@@ -5832,6 +5832,42 @@
|
|
|
5832
5832
|
}
|
|
5833
5833
|
]
|
|
5834
5834
|
},
|
|
5835
|
+
{
|
|
5836
|
+
"name": "uui-popover-container-scroll-level-1",
|
|
5837
|
+
"path": "./src/components/popover-container/popover-container-nestedslottester.element.ts",
|
|
5838
|
+
"description": "Outermost scroll level — blue outline.",
|
|
5839
|
+
"properties": [
|
|
5840
|
+
{
|
|
5841
|
+
"name": "styles",
|
|
5842
|
+
"type": "CSSResult",
|
|
5843
|
+
"default": "\"css`\\n .scroll-host {\\n height: 200px;\\n overflow: auto;\\n outline: 2px dashed royalblue;\\n width: 320px;\\n }\\n .spacer {\\n height: 140px;\\n }\\n `\""
|
|
5844
|
+
}
|
|
5845
|
+
]
|
|
5846
|
+
},
|
|
5847
|
+
{
|
|
5848
|
+
"name": "uui-popover-container-scroll-level-2",
|
|
5849
|
+
"path": "./src/components/popover-container/popover-container-nestedslottester.element.ts",
|
|
5850
|
+
"description": "Middle scroll level — orange outline.",
|
|
5851
|
+
"properties": [
|
|
5852
|
+
{
|
|
5853
|
+
"name": "styles",
|
|
5854
|
+
"type": "CSSResult",
|
|
5855
|
+
"default": "\"css`\\n .scroll-host {\\n height: 180px;\\n overflow: auto;\\n outline: 2px dashed darkorange;\\n width: 290px;\\n }\\n .spacer {\\n height: 120px;\\n }\\n `\""
|
|
5856
|
+
}
|
|
5857
|
+
]
|
|
5858
|
+
},
|
|
5859
|
+
{
|
|
5860
|
+
"name": "uui-popover-container-scroll-level-3",
|
|
5861
|
+
"path": "./src/components/popover-container/popover-container-nestedslottester.element.ts",
|
|
5862
|
+
"description": "Innermost scroll level — green outline.",
|
|
5863
|
+
"properties": [
|
|
5864
|
+
{
|
|
5865
|
+
"name": "styles",
|
|
5866
|
+
"type": "CSSResult",
|
|
5867
|
+
"default": "\"css`\\n .scroll-host {\\n height: 160px;\\n overflow: auto;\\n outline: 2px dashed green;\\n width: 260px;\\n }\\n .spacer {\\n height: 100px;\\n }\\n `\""
|
|
5868
|
+
}
|
|
5869
|
+
]
|
|
5870
|
+
},
|
|
5835
5871
|
{
|
|
5836
5872
|
"name": "uui-popover-container-shadowdomtester",
|
|
5837
5873
|
"path": "./src/components/popover-container/popover-container-shadowdomtester.element.ts"
|
|
@@ -20,6 +20,7 @@ export declare class UUIBreadcrumbItemElement extends LitElement {
|
|
|
20
20
|
* @default 'false'
|
|
21
21
|
*/
|
|
22
22
|
lastItem: boolean;
|
|
23
|
+
private _onKeydown;
|
|
23
24
|
renderLinkAndSeparator(): import("lit-html").TemplateResult<1>;
|
|
24
25
|
renderCurrent(): import("lit-html").TemplateResult<1>;
|
|
25
26
|
render(): import("lit-html").TemplateResult<1>;
|
|
@@ -17,8 +17,19 @@ const _UUIBreadcrumbItemElement = class _UUIBreadcrumbItemElement extends LitEle
|
|
|
17
17
|
connectedCallback() {
|
|
18
18
|
super.connectedCallback();
|
|
19
19
|
}
|
|
20
|
+
_onKeydown(e) {
|
|
21
|
+
if (e.key === "Enter") {
|
|
22
|
+
e.currentTarget.click();
|
|
23
|
+
}
|
|
24
|
+
}
|
|
20
25
|
renderLinkAndSeparator() {
|
|
21
|
-
const item = this.href ? html`<a id="link" href=${this.href}><slot></slot></a>` : html`<span
|
|
26
|
+
const item = this.href ? html`<a id="link" href=${this.href}><slot></slot></a>` : html`<span
|
|
27
|
+
id="link"
|
|
28
|
+
tabindex="0"
|
|
29
|
+
role="link"
|
|
30
|
+
@keydown=${this._onKeydown}
|
|
31
|
+
><slot></slot
|
|
32
|
+
></span>`;
|
|
22
33
|
return html`${item}<span part="separator"></span>`;
|
|
23
34
|
}
|
|
24
35
|
renderCurrent() {
|
|
@@ -36,17 +47,23 @@ _UUIBreadcrumbItemElement.styles = [
|
|
|
36
47
|
}
|
|
37
48
|
|
|
38
49
|
a,
|
|
39
|
-
a:visited
|
|
50
|
+
a:visited,
|
|
51
|
+
span#link {
|
|
40
52
|
color: currentColor;
|
|
53
|
+
cursor: pointer;
|
|
54
|
+
text-decoration: underline;
|
|
41
55
|
}
|
|
42
|
-
a:hover
|
|
56
|
+
a:hover,
|
|
57
|
+
span#link:hover {
|
|
43
58
|
color: var(--uui-color-interactive-emphasis);
|
|
44
59
|
}
|
|
45
|
-
a:focus
|
|
60
|
+
a:focus,
|
|
61
|
+
span#link:focus {
|
|
46
62
|
color: var(--uui-color-focus);
|
|
47
63
|
}
|
|
48
64
|
|
|
49
|
-
a:focus-visible
|
|
65
|
+
a:focus-visible,
|
|
66
|
+
span#link:focus-visible {
|
|
50
67
|
border-radius: var(--uui-border-radius);
|
|
51
68
|
outline: 2px solid var(--uui-color-focus);
|
|
52
69
|
}
|
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"breadcrumb-item.element.js","sources":["../../../src/components/breadcrumbs/breadcrumb-item.element.ts"],"sourcesContent":["import { css, html, LitElement } from 'lit';\nimport { property } from 'lit/decorators.js';\n\n/**\n * A breadcrumb-item to be used with the breadcrumbs component.\n * @element uui-breadcrumb-item\n * @slot - This slot displays elements inside the breadcrumb\n * @csspart separator - change the content of the after element of this part to change the separator\n */\nexport class UUIBreadcrumbItemElement extends LitElement {\n connectedCallback() {\n super.connectedCallback();\n }\n\n /**\n * Specifies the link href.\n * @type {String}\n * @default undefined\n */\n @property()\n href?: string;\n\n /**\n * Specifies if the element is the last item in the uui-breadcrumbs. Last item will not render as a link\n * @type {Boolean}\n * @attr last-item\n * @default 'false'\n */\n @property({ type: Boolean, attribute: 'last-item' })\n lastItem = false;\n\n renderLinkAndSeparator() {\n const item = this.href\n ? html`<a id=\"link\" href=${this.href}><slot></slot></a>`\n : html`<span
|
|
1
|
+
{"version":3,"file":"breadcrumb-item.element.js","sources":["../../../src/components/breadcrumbs/breadcrumb-item.element.ts"],"sourcesContent":["import { css, html, LitElement } from 'lit';\nimport { property } from 'lit/decorators.js';\n\n/**\n * A breadcrumb-item to be used with the breadcrumbs component.\n * @element uui-breadcrumb-item\n * @slot - This slot displays elements inside the breadcrumb\n * @csspart separator - change the content of the after element of this part to change the separator\n */\nexport class UUIBreadcrumbItemElement extends LitElement {\n connectedCallback() {\n super.connectedCallback();\n }\n\n /**\n * Specifies the link href.\n * @type {String}\n * @default undefined\n */\n @property()\n href?: string;\n\n /**\n * Specifies if the element is the last item in the uui-breadcrumbs. Last item will not render as a link\n * @type {Boolean}\n * @attr last-item\n * @default 'false'\n */\n @property({ type: Boolean, attribute: 'last-item' })\n lastItem = false;\n\n private _onKeydown(e: KeyboardEvent) {\n if (e.key === 'Enter') {\n (e.currentTarget as HTMLElement).click();\n }\n }\n\n renderLinkAndSeparator() {\n const item = this.href\n ? html`<a id=\"link\" href=${this.href}><slot></slot></a>`\n : html`<span\n id=\"link\"\n tabindex=\"0\"\n role=\"link\"\n @keydown=${this._onKeydown}\n ><slot></slot\n ></span>`;\n\n return html`${item}<span part=\"separator\"></span>`;\n }\n\n renderCurrent() {\n return html`<span id=\"last-item\"><slot></slot></span>`;\n }\n\n render() {\n return html`${this.lastItem\n ? this.renderCurrent()\n : this.renderLinkAndSeparator()}`;\n }\n\n static override readonly styles = [\n css`\n :host {\n font-size: var(--uui-type-small-size);\n color: currentColor;\n }\n\n a,\n a:visited,\n span#link {\n color: currentColor;\n cursor: pointer;\n text-decoration: underline;\n }\n a:hover,\n span#link:hover {\n color: var(--uui-color-interactive-emphasis);\n }\n a:focus,\n span#link:focus {\n color: var(--uui-color-focus);\n }\n\n a:focus-visible,\n span#link:focus-visible {\n border-radius: var(--uui-border-radius);\n outline: 2px solid var(--uui-color-focus);\n }\n\n [part='separator']::after {\n content: '/';\n speak: never;\n position: relative;\n top: 1px;\n margin: -3px 1px 0;\n color: var(--uui-color-border);\n }\n\n #link,\n #last-item {\n padding: 0 4px;\n max-width: 150px;\n white-space: nowrap;\n overflow: hidden;\n text-overflow: ellipsis;\n }\n `,\n ];\n}\n"],"names":[],"mappings":";;;;;;;;;;;AASO,MAAM,4BAAN,MAAM,kCAAiC,WAAW;AAAA,EAAlD,cAAA;AAAA,UAAA,GAAA,SAAA;AAoBL,SAAA,WAAW;AAAA,EAAA;AAAA,EAnBX,oBAAoB;AAClB,UAAM,kBAAA;AAAA,EACR;AAAA,EAmBQ,WAAW,GAAkB;AACnC,QAAI,EAAE,QAAQ,SAAS;AACpB,QAAE,cAA8B,MAAA;AAAA,IACnC;AAAA,EACF;AAAA,EAEA,yBAAyB;AACvB,UAAM,OAAO,KAAK,OACd,yBAAyB,KAAK,IAAI,uBAClC;AAAA;AAAA;AAAA;AAAA,qBAIa,KAAK,UAAU;AAAA;AAAA;AAIhC,WAAO,OAAO,IAAI;AAAA,EACpB;AAAA,EAEA,gBAAgB;AACd,WAAO;AAAA,EACT;AAAA,EAEA,SAAS;AACP,WAAO,OAAO,KAAK,WACf,KAAK,kBACL,KAAK,wBAAwB;AAAA,EACnC;AAkDF;AAhDE,0BAAyB,SAAS;AAAA,EAChC;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AArDG,IAAM,2BAAN;AAWL,gBAAA;AAAA,EADC,SAAA;AAAS,GAVC,yBAWX,WAAA,MAAA;AASA,gBAAA;AAAA,EADC,SAAS,EAAE,MAAM,SAAS,WAAW,aAAa;AAAA,GAnBxC,yBAoBX,WAAA,UAAA;"}
|
|
@@ -189,9 +189,9 @@ _UUIInputElement.styles = [
|
|
|
189
189
|
var(--uui-input-border-color, var(--uui-color-border));
|
|
190
190
|
border-radius: var(--uui-input-border-radius, var(--uui-border-radius));
|
|
191
191
|
min-width: 0;
|
|
192
|
+
overflow: hidden;
|
|
192
193
|
|
|
193
|
-
--uui-input-padding: 1px var(--uui-size-
|
|
194
|
-
var(--uui-size-space-3);
|
|
194
|
+
--uui-input-padding: 1px var(--uui-size-3);
|
|
195
195
|
--uui-button-height: 100%;
|
|
196
196
|
--uui-button-border-radius: var(
|
|
197
197
|
--uui-input-border-radius,
|
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"input.element.js","sources":["../../../src/components/input/input.element.ts"],"sourcesContent":["import {\n UUIFormControlWithBasicsMixin,\n LabelMixin,\n} from '../../internal/mixins/index.js';\nimport { css, html, LitElement } from 'lit';\nimport { property, query } from 'lit/decorators.js';\nimport { ifDefined } from 'lit/directives/if-defined.js';\n\nimport { UUIInputEvent } from './UUIInputEvent.js';\n\nexport type InputType =\n | 'text'\n | 'tel'\n | 'url'\n | 'email'\n | 'password'\n | 'search'\n | 'month'\n | 'week'\n | 'time'\n | 'date'\n | 'datetime-local'\n | 'number'\n | 'color';\n\nexport type InputMode =\n | 'text'\n | 'none'\n | 'decimal'\n | 'numeric'\n | 'tel'\n | 'search'\n | 'email'\n | 'url';\n\n/**\n * Custom element wrapping the native input element.This is a formAssociated element, meaning it can participate in a native HTMLForm. A name:value pair will be submitted.\n * @element uui-input\n * @slot prepend - for components to render to the left of the input.\n * @slot append - for components to render to the right of the input.\n * @property {boolean} spellcheck - get/set native spellcheck attribute\n * @attribute spellcheck - native spellcheck attribute\n * @property {string} value - get/set the value of the input\n * @attribute value - get/set the value of the input\n * @property {string} name - get/set the name of the input\n * @attribute name - get/set the name of the input\n * @fires UUIInputEvent#change on change\n * @fires InputEvent#input on input\n * @fires KeyboardEvent#keyup on keyup\n * @cssprop --uui-input-height - Height of the element\n * @cssprop --uui-input-background-color - Background color of the element\n * @cssprop --uui-input-background-color-disabled - Background color when disabled\n * @cssprop --uui-input-background-color-readonly - Background color when readonly\n * @cssprop --uui-input-border-width - Border width\n * @cssprop --uui-input-border-radius - Border radius\n * @cssprop --uui-input-border-color - Border color\n * @cssprop --uui-input-border-color-hover - Border color on hover\n * @cssprop --uui-input-border-color-focus - Border color on focus\n * @cssprop --uui-input-border-color-disabled - Border color when disabled\n * @cssprop --uui-input-border-color-readonly - Border color when readonly\n */\nexport class UUIInputElement extends UUIFormControlWithBasicsMixin(\n LabelMixin('', LitElement),\n '',\n) {\n /**\n * This is a static class field indicating that the element is can be used inside a native form and participate in its events. It may require a polyfill, check support here https://developer.mozilla.org/en-US/docs/Web/API/HTMLElement/attachInternals. Read more about form controls here https://web.dev/more-capable-form-controls/\n * @type {boolean}\n */\n static readonly formAssociated = true;\n\n /**\n * Sets the min value of the input.\n * Examples: the first date the user may pick in date and datetime-local, or the min numeric value the user can pick in a number input.\n * @type {number | string}\n * @attr\n * @default undefined\n */\n @property()\n min?: number | string;\n\n /**\n * Sets the minimum length of the value of the input.\n * @type {number}\n * @attr\n * @default undefined\n */\n @property({ type: Number })\n minlength?: number;\n\n /**\n * Minlength validation message.\n * @attr minlength-message\n * @default\n */\n @property({ attribute: 'minlength-message' })\n minlengthMessage: string | ((charsLeft: number) => string) = charsLeft =>\n `${charsLeft} characters left`;\n\n /**\n * Sets the max value of the input.\n * Examples: the last date the user may pick in date and datetime-local, or the max numeric value the user can pick in a number input.\n * @type {number | string}\n * @attr\n * @default undefined\n */\n @property()\n max?: number | string;\n\n /**\n * Sets the maximum length of the value of the input.\n * @type {number}\n * @attr\n * @default undefined\n */\n @property({ type: Number })\n maxlength?: number;\n\n /**\n * Maxlength validation message.\n * @attr maxlength-message\n * @default\n */\n @property({ attribute: 'maxlength-message' })\n maxlengthMessage: string | ((max: number, current: number) => string) = (\n max,\n current,\n ) => `Maximum ${max} characters, ${current - max} too many.`;\n\n /**\n * Specifies the interval between legal numbers of the input\n * @type {number}\n * @attr\n * @default undefined\n */\n @property({ type: Number })\n step?: number;\n\n /**\n * Disables the input.\n * @type {boolean}\n * @attr\n * @default false\n */\n @property({ type: Boolean, reflect: true })\n disabled = false;\n\n /**\n * Sets the input to readonly mode, meaning value cannot be changed but still able to read and select its content.\n * @type {boolean}\n * @attr\n * @default false\n */\n @property({ type: Boolean, reflect: true })\n readonly = false;\n\n /**\n * Defines the input placeholder.\n * @type {string}\n * @attr\n * @default ''\n */\n @property()\n placeholder = '';\n\n /**\n * Defines the input autocomplete.\n * @type {string}\n * @attr\n * @default undefined\n */\n @property()\n autocomplete?: string;\n\n /**\n * Sets the input width to fit the value or placeholder if empty\n * @type {boolean}\n * @attr auto-width\n */\n @property({ type: Boolean, reflect: true, attribute: 'auto-width' })\n autoWidth = false;\n\n /**\n * This property specifies the type of input that will be rendered.\n * @see {@link https://developer.mozilla.org/en-US/docs/Web/HTML/Element/input#input_types|MDN} for further information\n * @type {'text' | 'tel' | 'url' | 'email' | 'password' | 'date' | 'month' | 'week' | 'time' | 'datetime-local' | 'number' | 'color'}\n * @attr\n * @default text\n */\n @property({ type: String })\n get type(): InputType {\n return this._type;\n }\n set type(value: InputType) {\n this._type = value;\n }\n\n /**\n * The inputmode global attribute is an enumerated attribute that hints at the type of data that might be entered by the user while editing the element or its contents. This allows a browser to display an appropriate virtual keyboard.\n * @see {@link https://developer.mozilla.org/en-US/docs/Web/HTML/Global_attributes/inputmode|MDN} for further information\n * @type {'text' | 'none' | 'decimal' | 'number' | 'tel' | 'search' | 'email' | 'url'}\n * @attr\n * @default text\n */\n @property({ attribute: 'inputmode' })\n inputMode: InputMode = 'text';\n\n /**\n * Validates the input based on the Regex pattern\n * @type {string}\n * @attr\n */\n @property({ type: String })\n pattern?: string;\n\n /**\n * Set the input tabindex, set this to `-1` to avoid tabbing into the input.\n * @type {number}\n * @attr\n */\n @property({ type: Number, reflect: false, attribute: 'tabindex' })\n tabIndex: number = 0;\n\n @query('#input')\n readonly _input!: HTMLInputElement;\n\n private _type: InputType = 'text';\n\n constructor() {\n super();\n\n this.addEventListener('keydown', this.#onKeyDown);\n\n this.addValidator(\n 'tooShort',\n () => {\n const label = this.minlengthMessage;\n if (typeof label === 'function') {\n return label(\n this.minlength ? this.minlength - String(this.value).length : 0,\n );\n }\n return label;\n },\n () => !!this.minlength && String(this.value).length < this.minlength,\n );\n this.addValidator(\n 'tooLong',\n () => {\n const label = this.maxlengthMessage;\n if (typeof label === 'function') {\n return label(this.maxlength ?? 0, String(this.value).length);\n }\n return label;\n },\n () => !!this.maxlength && String(this.value).length > this.maxlength,\n );\n\n this.updateComplete.then(() => {\n this.addFormControlElement(this._input);\n });\n }\n\n #onKeyDown(e: KeyboardEvent): void {\n if (this.type !== 'color' && e.key == 'Enter') {\n this.submit();\n }\n }\n\n /**\n * Removes focus from the input.\n */\n async blur() {\n await this.updateComplete;\n this._input.blur();\n }\n\n /**\n * This method enables <label for=\"...\"> to focus the input\n */\n async focus() {\n await this.updateComplete;\n this._input.focus();\n }\n\n /**\n * Selects all the text in the input.\n */\n async select() {\n await this.updateComplete;\n this._input.select();\n }\n\n protected getFormElement(): HTMLElement {\n return this.shadowRoot?.querySelector('input') as HTMLElement;\n }\n\n protected onInput(e: Event) {\n e.stopPropagation();\n this.value = (e.target as HTMLInputElement).value;\n\n this.dispatchEvent(new UUIInputEvent(UUIInputEvent.INPUT));\n }\n\n protected onChange(e: Event) {\n e.stopPropagation();\n this.pristine = false;\n\n this.dispatchEvent(new UUIInputEvent(UUIInputEvent.CHANGE));\n }\n\n protected renderPrepend() {\n return html`<slot name=\"prepend\"></slot>`;\n }\n\n protected renderAppend() {\n return html`<slot name=\"append\"></slot>`;\n }\n\n render() {\n return html`\n ${this.renderPrepend()}\n <div id=\"inner\">\n <slot></slot>\n ${this.autoWidth ? this.renderInputWithAutoWidth() : this.renderInput()}\n </div>\n ${this.renderAppend()}\n `;\n }\n\n private renderInputWithAutoWidth() {\n return html`<div id=\"autoWidth\">\n ${this.renderInput()}${this.renderAutoWidthBackground()}\n </div>`;\n }\n\n renderInput() {\n return html`<input\n id=\"input\"\n size=${ifDefined(this.autoWidth ? '1' : undefined)}\n .type=${this.type}\n .value=${this.value as string}\n .name=${this.name}\n pattern=${ifDefined(this.pattern)}\n min=${ifDefined(this.min)}\n max=${ifDefined(this.max)}\n step=${ifDefined(this.step)}\n spellcheck=${this.spellcheck}\n autocomplete=${ifDefined(this.autocomplete as any)}\n placeholder=${ifDefined(this.placeholder)}\n aria-label=${ifDefined(\n this.getAttribute('aria-label') || this.label || undefined,\n )}\n aria-labelledby=${ifDefined(\n this.getAttribute('aria-labelledby') || undefined,\n )}\n inputmode=${ifDefined(this.inputMode)}\n ?disabled=${this.disabled}\n ?autofocus=${this.autofocus}\n ?required=${this.required}\n ?readonly=${this.readonly}\n tabindex=${ifDefined(this.tabIndex)}\n @input=${this.onInput}\n @change=${this.onChange} />`;\n }\n\n private renderAutoWidthBackground() {\n return html` <div id=\"auto\" aria-hidden=\"true\">${this.renderText()}</div>`;\n }\n\n private renderText() {\n return html`${(this.value as string).length > 0\n ? this.value\n : this.placeholder}`;\n }\n\n static override readonly styles = [\n css`\n :host {\n position: relative;\n display: inline-flex;\n align-items: stretch;\n height: var(--uui-input-height, var(--uui-size-11));\n text-align: left;\n color: var(--uui-color-text);\n color-scheme: var(--uui-color-scheme, normal);\n box-sizing: border-box;\n background-color: var(\n --uui-input-background-color,\n var(--uui-color-surface)\n );\n border: var(--uui-input-border-width, 1px) solid\n var(--uui-input-border-color, var(--uui-color-border));\n border-radius: var(--uui-input-border-radius, var(--uui-border-radius));\n min-width: 0;\n\n --uui-input-padding: 1px var(--uui-size-space-3) 3px\n var(--uui-size-space-3);\n --uui-button-height: 100%;\n --uui-button-border-radius: var(\n --uui-input-border-radius,\n var(--uui-border-radius)\n );\n --auto-width-text-margin-right: 0;\n --auto-width-text-margin-left: 0;\n }\n\n #autoWidth {\n position: relative;\n display: flex;\n flex-direction: column;\n align-items: stretch;\n justify-content: center;\n flex-grow: 1;\n flex-shrink: 1;\n min-width: 0;\n }\n\n #auto {\n border: 0 1px solid transparent;\n visibility: hidden;\n white-space: pre;\n z-index: -1;\n height: 0px;\n padding: 0 var(--uui-size-space-3);\n margin: 0 var(--auto-width-text-margin-right) 0\n var(--auto-width-text-margin-left);\n }\n\n :host(:hover) {\n border-color: var(\n --uui-input-border-color-hover,\n var(--uui-color-border-standalone)\n );\n }\n /* TODO: Fix so we dont get double outline when there is focus on things in the slot. */\n :host(:focus-within) {\n border-color: var(\n --uui-input-border-color-focus,\n var(--uui-color-border-emphasis)\n );\n outline: 2px solid var(--uui-color-focus);\n }\n :host(:focus) {\n border-color: var(\n --uui-input-border-color-focus,\n var(--uui-color-border-emphasis)\n );\n }\n :host([disabled]) {\n background-color: var(\n --uui-input-background-color-disabled,\n var(--uui-color-disabled)\n );\n border-color: var(\n --uui-input-border-color-disabled,\n var(--uui-color-disabled)\n );\n\n color: var(--uui-color-disabled-contrast);\n }\n :host([disabled]) input {\n -webkit-text-fill-color: var(\n --uui-color-disabled-contrast\n ); /* required on Safari and IOS */\n }\n :host([readonly]) {\n background-color: var(\n --uui-input-background-color-readonly,\n var(--uui-color-disabled)\n );\n border-color: var(\n --uui-input-border-color-readonly,\n var(--uui-color-disabled-standalone)\n );\n }\n\n :host(:not([pristine]):invalid),\n /* polyfill support */\n :host(:not([pristine])[internals-invalid]) {\n border-color: var(--uui-color-invalid);\n }\n\n input {\n font-family: inherit;\n padding: var(--uui-input-padding);\n font-size: inherit;\n color: inherit;\n border-radius: var(--uui-border-radius);\n box-sizing: border-box;\n border: none;\n background: none;\n min-width: 0;\n flex-grow: 1;\n flex-shrink: 1;\n height: inherit;\n text-align: inherit;\n outline: none;\n text-overflow: ellipsis;\n line-height: 1;\n flex: 1 1 auto;\n min-width: 60px;\n }\n\n input[type='password']::-ms-reveal {\n display: none;\n }\n\n /* TODO: make sure color looks good, or remove it as an option as we want to provide color-picker component */\n input[type='color'] {\n width: 30px;\n padding: 0;\n border: none;\n }\n\n slot[name='prepend'],\n slot[name='append'] {\n display: flex;\n align-items: center;\n line-height: 1;\n height: 100%;\n min-width: 0;\n }\n\n uui-input,\n uui-input-lock,\n ::slotted(uui-input),\n ::slotted(uui-input-lock) {\n height: 100%;\n --uui-input-border-width: 0;\n }\n\n uui-button,\n ::slotted(uui-button) {\n height: 100%;\n --uui-button-border-width: 0;\n }\n\n #inner {\n display: flex;\n flex-wrap: wrap;\n align-items: center;\n gap: 4px;\n flex: 1 1 auto;\n min-width: 0;\n padding: 2px;\n }\n `,\n ];\n}\n"],"names":[],"mappings":"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"}
|
|
1
|
+
{"version":3,"file":"input.element.js","sources":["../../../src/components/input/input.element.ts"],"sourcesContent":["import {\n UUIFormControlWithBasicsMixin,\n LabelMixin,\n} from '../../internal/mixins/index.js';\nimport { css, html, LitElement } from 'lit';\nimport { property, query } from 'lit/decorators.js';\nimport { ifDefined } from 'lit/directives/if-defined.js';\n\nimport { UUIInputEvent } from './UUIInputEvent.js';\n\nexport type InputType =\n | 'text'\n | 'tel'\n | 'url'\n | 'email'\n | 'password'\n | 'search'\n | 'month'\n | 'week'\n | 'time'\n | 'date'\n | 'datetime-local'\n | 'number'\n | 'color';\n\nexport type InputMode =\n | 'text'\n | 'none'\n | 'decimal'\n | 'numeric'\n | 'tel'\n | 'search'\n | 'email'\n | 'url';\n\n/**\n * Custom element wrapping the native input element.This is a formAssociated element, meaning it can participate in a native HTMLForm. A name:value pair will be submitted.\n * @element uui-input\n * @slot prepend - for components to render to the left of the input.\n * @slot append - for components to render to the right of the input.\n * @property {boolean} spellcheck - get/set native spellcheck attribute\n * @attribute spellcheck - native spellcheck attribute\n * @property {string} value - get/set the value of the input\n * @attribute value - get/set the value of the input\n * @property {string} name - get/set the name of the input\n * @attribute name - get/set the name of the input\n * @fires UUIInputEvent#change on change\n * @fires InputEvent#input on input\n * @fires KeyboardEvent#keyup on keyup\n * @cssprop --uui-input-height - Height of the element\n * @cssprop --uui-input-background-color - Background color of the element\n * @cssprop --uui-input-background-color-disabled - Background color when disabled\n * @cssprop --uui-input-background-color-readonly - Background color when readonly\n * @cssprop --uui-input-border-width - Border width\n * @cssprop --uui-input-border-radius - Border radius\n * @cssprop --uui-input-border-color - Border color\n * @cssprop --uui-input-border-color-hover - Border color on hover\n * @cssprop --uui-input-border-color-focus - Border color on focus\n * @cssprop --uui-input-border-color-disabled - Border color when disabled\n * @cssprop --uui-input-border-color-readonly - Border color when readonly\n */\nexport class UUIInputElement extends UUIFormControlWithBasicsMixin(\n LabelMixin('', LitElement),\n '',\n) {\n /**\n * This is a static class field indicating that the element is can be used inside a native form and participate in its events. It may require a polyfill, check support here https://developer.mozilla.org/en-US/docs/Web/API/HTMLElement/attachInternals. Read more about form controls here https://web.dev/more-capable-form-controls/\n * @type {boolean}\n */\n static readonly formAssociated = true;\n\n /**\n * Sets the min value of the input.\n * Examples: the first date the user may pick in date and datetime-local, or the min numeric value the user can pick in a number input.\n * @type {number | string}\n * @attr\n * @default undefined\n */\n @property()\n min?: number | string;\n\n /**\n * Sets the minimum length of the value of the input.\n * @type {number}\n * @attr\n * @default undefined\n */\n @property({ type: Number })\n minlength?: number;\n\n /**\n * Minlength validation message.\n * @attr minlength-message\n * @default\n */\n @property({ attribute: 'minlength-message' })\n minlengthMessage: string | ((charsLeft: number) => string) = charsLeft =>\n `${charsLeft} characters left`;\n\n /**\n * Sets the max value of the input.\n * Examples: the last date the user may pick in date and datetime-local, or the max numeric value the user can pick in a number input.\n * @type {number | string}\n * @attr\n * @default undefined\n */\n @property()\n max?: number | string;\n\n /**\n * Sets the maximum length of the value of the input.\n * @type {number}\n * @attr\n * @default undefined\n */\n @property({ type: Number })\n maxlength?: number;\n\n /**\n * Maxlength validation message.\n * @attr maxlength-message\n * @default\n */\n @property({ attribute: 'maxlength-message' })\n maxlengthMessage: string | ((max: number, current: number) => string) = (\n max,\n current,\n ) => `Maximum ${max} characters, ${current - max} too many.`;\n\n /**\n * Specifies the interval between legal numbers of the input\n * @type {number}\n * @attr\n * @default undefined\n */\n @property({ type: Number })\n step?: number;\n\n /**\n * Disables the input.\n * @type {boolean}\n * @attr\n * @default false\n */\n @property({ type: Boolean, reflect: true })\n disabled = false;\n\n /**\n * Sets the input to readonly mode, meaning value cannot be changed but still able to read and select its content.\n * @type {boolean}\n * @attr\n * @default false\n */\n @property({ type: Boolean, reflect: true })\n readonly = false;\n\n /**\n * Defines the input placeholder.\n * @type {string}\n * @attr\n * @default ''\n */\n @property()\n placeholder = '';\n\n /**\n * Defines the input autocomplete.\n * @type {string}\n * @attr\n * @default undefined\n */\n @property()\n autocomplete?: string;\n\n /**\n * Sets the input width to fit the value or placeholder if empty\n * @type {boolean}\n * @attr auto-width\n */\n @property({ type: Boolean, reflect: true, attribute: 'auto-width' })\n autoWidth = false;\n\n /**\n * This property specifies the type of input that will be rendered.\n * @see {@link https://developer.mozilla.org/en-US/docs/Web/HTML/Element/input#input_types|MDN} for further information\n * @type {'text' | 'tel' | 'url' | 'email' | 'password' | 'date' | 'month' | 'week' | 'time' | 'datetime-local' | 'number' | 'color'}\n * @attr\n * @default text\n */\n @property({ type: String })\n get type(): InputType {\n return this._type;\n }\n set type(value: InputType) {\n this._type = value;\n }\n\n /**\n * The inputmode global attribute is an enumerated attribute that hints at the type of data that might be entered by the user while editing the element or its contents. This allows a browser to display an appropriate virtual keyboard.\n * @see {@link https://developer.mozilla.org/en-US/docs/Web/HTML/Global_attributes/inputmode|MDN} for further information\n * @type {'text' | 'none' | 'decimal' | 'number' | 'tel' | 'search' | 'email' | 'url'}\n * @attr\n * @default text\n */\n @property({ attribute: 'inputmode' })\n inputMode: InputMode = 'text';\n\n /**\n * Validates the input based on the Regex pattern\n * @type {string}\n * @attr\n */\n @property({ type: String })\n pattern?: string;\n\n /**\n * Set the input tabindex, set this to `-1` to avoid tabbing into the input.\n * @type {number}\n * @attr\n */\n @property({ type: Number, reflect: false, attribute: 'tabindex' })\n tabIndex: number = 0;\n\n @query('#input')\n readonly _input!: HTMLInputElement;\n\n private _type: InputType = 'text';\n\n constructor() {\n super();\n\n this.addEventListener('keydown', this.#onKeyDown);\n\n this.addValidator(\n 'tooShort',\n () => {\n const label = this.minlengthMessage;\n if (typeof label === 'function') {\n return label(\n this.minlength ? this.minlength - String(this.value).length : 0,\n );\n }\n return label;\n },\n () => !!this.minlength && String(this.value).length < this.minlength,\n );\n this.addValidator(\n 'tooLong',\n () => {\n const label = this.maxlengthMessage;\n if (typeof label === 'function') {\n return label(this.maxlength ?? 0, String(this.value).length);\n }\n return label;\n },\n () => !!this.maxlength && String(this.value).length > this.maxlength,\n );\n\n this.updateComplete.then(() => {\n this.addFormControlElement(this._input);\n });\n }\n\n #onKeyDown(e: KeyboardEvent): void {\n if (this.type !== 'color' && e.key == 'Enter') {\n this.submit();\n }\n }\n\n /**\n * Removes focus from the input.\n */\n async blur() {\n await this.updateComplete;\n this._input.blur();\n }\n\n /**\n * This method enables <label for=\"...\"> to focus the input\n */\n async focus() {\n await this.updateComplete;\n this._input.focus();\n }\n\n /**\n * Selects all the text in the input.\n */\n async select() {\n await this.updateComplete;\n this._input.select();\n }\n\n protected getFormElement(): HTMLElement {\n return this.shadowRoot?.querySelector('input') as HTMLElement;\n }\n\n protected onInput(e: Event) {\n e.stopPropagation();\n this.value = (e.target as HTMLInputElement).value;\n\n this.dispatchEvent(new UUIInputEvent(UUIInputEvent.INPUT));\n }\n\n protected onChange(e: Event) {\n e.stopPropagation();\n this.pristine = false;\n\n this.dispatchEvent(new UUIInputEvent(UUIInputEvent.CHANGE));\n }\n\n protected renderPrepend() {\n return html`<slot name=\"prepend\"></slot>`;\n }\n\n protected renderAppend() {\n return html`<slot name=\"append\"></slot>`;\n }\n\n render() {\n return html`\n ${this.renderPrepend()}\n <div id=\"inner\">\n <slot></slot>\n ${this.autoWidth ? this.renderInputWithAutoWidth() : this.renderInput()}\n </div>\n ${this.renderAppend()}\n `;\n }\n\n private renderInputWithAutoWidth() {\n return html`<div id=\"autoWidth\">\n ${this.renderInput()}${this.renderAutoWidthBackground()}\n </div>`;\n }\n\n renderInput() {\n return html`<input\n id=\"input\"\n size=${ifDefined(this.autoWidth ? '1' : undefined)}\n .type=${this.type}\n .value=${this.value as string}\n .name=${this.name}\n pattern=${ifDefined(this.pattern)}\n min=${ifDefined(this.min)}\n max=${ifDefined(this.max)}\n step=${ifDefined(this.step)}\n spellcheck=${this.spellcheck}\n autocomplete=${ifDefined(this.autocomplete as any)}\n placeholder=${ifDefined(this.placeholder)}\n aria-label=${ifDefined(\n this.getAttribute('aria-label') || this.label || undefined,\n )}\n aria-labelledby=${ifDefined(\n this.getAttribute('aria-labelledby') || undefined,\n )}\n inputmode=${ifDefined(this.inputMode)}\n ?disabled=${this.disabled}\n ?autofocus=${this.autofocus}\n ?required=${this.required}\n ?readonly=${this.readonly}\n tabindex=${ifDefined(this.tabIndex)}\n @input=${this.onInput}\n @change=${this.onChange} />`;\n }\n\n private renderAutoWidthBackground() {\n return html` <div id=\"auto\" aria-hidden=\"true\">${this.renderText()}</div>`;\n }\n\n private renderText() {\n return html`${(this.value as string).length > 0\n ? this.value\n : this.placeholder}`;\n }\n\n static override readonly styles = [\n css`\n :host {\n position: relative;\n display: inline-flex;\n align-items: stretch;\n height: var(--uui-input-height, var(--uui-size-11));\n text-align: left;\n color: var(--uui-color-text);\n color-scheme: var(--uui-color-scheme, normal);\n box-sizing: border-box;\n background-color: var(\n --uui-input-background-color,\n var(--uui-color-surface)\n );\n border: var(--uui-input-border-width, 1px) solid\n var(--uui-input-border-color, var(--uui-color-border));\n border-radius: var(--uui-input-border-radius, var(--uui-border-radius));\n min-width: 0;\n overflow: hidden;\n\n --uui-input-padding: 1px var(--uui-size-3);\n --uui-button-height: 100%;\n --uui-button-border-radius: var(\n --uui-input-border-radius,\n var(--uui-border-radius)\n );\n --auto-width-text-margin-right: 0;\n --auto-width-text-margin-left: 0;\n }\n\n #autoWidth {\n position: relative;\n display: flex;\n flex-direction: column;\n align-items: stretch;\n justify-content: center;\n flex-grow: 1;\n flex-shrink: 1;\n min-width: 0;\n }\n\n #auto {\n border: 0 1px solid transparent;\n visibility: hidden;\n white-space: pre;\n z-index: -1;\n height: 0px;\n padding: 0 var(--uui-size-space-3);\n margin: 0 var(--auto-width-text-margin-right) 0\n var(--auto-width-text-margin-left);\n }\n\n :host(:hover) {\n border-color: var(\n --uui-input-border-color-hover,\n var(--uui-color-border-standalone)\n );\n }\n /* TODO: Fix so we dont get double outline when there is focus on things in the slot. */\n :host(:focus-within) {\n border-color: var(\n --uui-input-border-color-focus,\n var(--uui-color-border-emphasis)\n );\n outline: 2px solid var(--uui-color-focus);\n }\n :host(:focus) {\n border-color: var(\n --uui-input-border-color-focus,\n var(--uui-color-border-emphasis)\n );\n }\n :host([disabled]) {\n background-color: var(\n --uui-input-background-color-disabled,\n var(--uui-color-disabled)\n );\n border-color: var(\n --uui-input-border-color-disabled,\n var(--uui-color-disabled)\n );\n\n color: var(--uui-color-disabled-contrast);\n }\n :host([disabled]) input {\n -webkit-text-fill-color: var(\n --uui-color-disabled-contrast\n ); /* required on Safari and IOS */\n }\n :host([readonly]) {\n background-color: var(\n --uui-input-background-color-readonly,\n var(--uui-color-disabled)\n );\n border-color: var(\n --uui-input-border-color-readonly,\n var(--uui-color-disabled-standalone)\n );\n }\n\n :host(:not([pristine]):invalid),\n /* polyfill support */\n :host(:not([pristine])[internals-invalid]) {\n border-color: var(--uui-color-invalid);\n }\n\n input {\n font-family: inherit;\n padding: var(--uui-input-padding);\n font-size: inherit;\n color: inherit;\n border-radius: var(--uui-border-radius);\n box-sizing: border-box;\n border: none;\n background: none;\n min-width: 0;\n flex-grow: 1;\n flex-shrink: 1;\n height: inherit;\n text-align: inherit;\n outline: none;\n text-overflow: ellipsis;\n line-height: 1;\n flex: 1 1 auto;\n min-width: 60px;\n }\n\n input[type='password']::-ms-reveal {\n display: none;\n }\n\n /* TODO: make sure color looks good, or remove it as an option as we want to provide color-picker component */\n input[type='color'] {\n width: 30px;\n padding: 0;\n border: none;\n }\n\n slot[name='prepend'],\n slot[name='append'] {\n display: flex;\n align-items: center;\n line-height: 1;\n height: 100%;\n min-width: 0;\n }\n\n uui-input,\n uui-input-lock,\n ::slotted(uui-input),\n ::slotted(uui-input-lock) {\n height: 100%;\n --uui-input-border-width: 0;\n }\n\n uui-button,\n ::slotted(uui-button) {\n height: 100%;\n --uui-button-border-width: 0;\n }\n\n #inner {\n display: flex;\n flex-wrap: wrap;\n align-items: center;\n gap: 4px;\n flex: 1 1 auto;\n min-width: 0;\n padding: 2px;\n }\n `,\n ];\n}\n"],"names":[],"mappings":"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"}
|
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"pagination.element.js","sources":["../../../src/components/pagination/pagination.element.ts"],"sourcesContent":["import type { UUIButtonElement } from '../button/button.js';\nimport { css, html, LitElement } from 'lit';\nimport { property, query, queryAll, state } from 'lit/decorators.js';\n\nimport { UUIPaginationEvent } from './UUIPaginationEvent.js';\n\nimport '../button/button.js';\nimport '../button-group/button-group.js';\n\n//this is how wide the button gets when it has 3 digits inside.\nconst PAGE_BUTTON_MAX_WIDTH = 45;\n\nconst limit = (val: number, min: number, max: number) => {\n return Math.min(Math.max(val, min), max);\n};\n\nconst arrayOfNumbers = (start: number, stop: number) => {\n return Array.from({ length: stop - start + 1 }, (_, i) => start + i);\n};\n\n/**\n * @element uui-pagination\n * @description Jump to a certain page and navigate to the next, last, previous or first page. The amount of visible page-buttons are adjusted to the available space.\n * @fires change - When clicked on the page button fires change event\n */\nexport class UUIPaginationElement extends LitElement {\n private readonly _observer = new ResizeObserver(\n this._calculateRange.bind(this),\n );\n\n connectedCallback() {\n super.connectedCallback();\n if (!this.hasAttribute('role')) this.setAttribute('role', 'navigation');\n this._visiblePages = this._generateVisiblePages(this.current);\n }\n\n disconnectedCallback() {\n this._observer.disconnect();\n }\n\n firstUpdated() {\n this._observer.observe(this._pagesGroup);\n\n this.updateLabel();\n this._calculateRange();\n }\n\n willUpdate(changedProperties: Map<string | number | symbol, unknown>) {\n if (changedProperties.has('current') || changedProperties.has('label')) {\n this.updateLabel();\n }\n }\n\n protected updateLabel() {\n this.ariaLabel = `${this.label || 'Pagination navigation'}. Current page: ${\n this.current\n }.`;\n }\n\n private _calculateRange() {\n const containerWidth = this.offsetWidth;\n\n // get all the buttons with .nav-button class and sum up their widths\n const navButtonsWidth = Array.from(this._navButtons).reduce(\n (totalWidth, button) => {\n return totalWidth + button.getBoundingClientRect().width;\n },\n 0,\n );\n\n // subtract width of nav-buttons from the pagination container\n const rangeBaseWidth = containerWidth - navButtonsWidth;\n\n // divide remaining width by max-width of page button (when it has 3 digits), then divide by 2 to get the range.\n // Range is number of buttons visible on either \"side\" of current pag button. So, if range === 5 we shall see 11 buttons in total - 5 before the current page and 5 after. This is why we divide by 2.\n const range = rangeBaseWidth / PAGE_BUTTON_MAX_WIDTH / 2;\n this._range = Math.max(0, Math.floor(range));\n this._visiblePages = this._generateVisiblePages(this.current);\n }\n\n private _generateVisiblePages(current: number) {\n let start: number;\n if (current < this._range) {\n start = 1;\n } else if (current < this.total - this._range) {\n start = current - this._range;\n } else {\n start = this.total - this._range * 2;\n }\n\n let stop: number;\n if (current <= this._range) {\n stop = this._range * 2 + 1;\n } else if (current < this.total - this._range) {\n stop = current + this._range;\n } else {\n stop = this.total;\n }\n\n const pages = arrayOfNumbers(\n limit(start, 1, this.total),\n limit(stop, 1, this.total),\n );\n\n return pages;\n }\n\n @queryAll('uui-button.nav')\n private readonly _navButtons!: Array<UUIButtonElement>;\n\n @query('#pages')\n private readonly _pagesGroup!: any;\n\n /**\n * This property is used to generate a proper `aria-label`. It will be announced by screen reader as: \"<<this.label>>. Current page: <<this.current>>\"\n * @type {string}\n * @attr\n */\n @property()\n label = '';\n\n /**\n * With this property you can overwrite aria-label.\n * @type {string}\n * @attr\n */\n @property({ reflect: true, attribute: 'aria-label' })\n ariaLabel = '';\n\n /**\n * This property is used to generate the name of the first button\n * @type {string}\n * @attr\n */\n @property()\n firstLabel: string = 'First';\n\n /**\n * This property is used to generate the name of the previous button\n * @type {string}\n * @attr\n */\n @property()\n previousLabel: string = 'Previous';\n\n /**\n * This property is used to generate the name of the next button\n * @type {string}\n * @attr\n */\n @property()\n nextLabel: string = 'Next';\n /**\n * This property is used to generate the name of the last button\n * @type {string}\n * @attr\n */\n @property()\n lastLabel: string = 'Last';\n\n private _total = 100;\n\n /**\n * Set the amount of pages to navigate.\n * @type {number}\n * @attr\n * @default: 1\n */\n @property({ type: Number })\n get total() {\n return this._total;\n }\n set total(newValue: number) {\n this._total = newValue;\n this._visiblePages = this._generateVisiblePages(this._current);\n this.requestUpdate('total', newValue);\n }\n\n @state()\n private _range = 0;\n\n @state()\n private _visiblePages: number[] = [];\n\n private _current = 1;\n\n /**\n * Define the current active page.\n * @type {number}\n * @attr\n */\n @property({ type: Number })\n get current() {\n return this._current;\n }\n set current(newValue: number) {\n const oldValue = this._current;\n this._current = limit(newValue, 1, this.total);\n this._visiblePages = this._generateVisiblePages(this._current);\n this.requestUpdate('current', oldValue);\n }\n\n /**\n * This method will change the page to a next one.\n * @memberof UUIPaginationElement\n */\n goToNextPage() {\n this.current++;\n this.dispatchEvent(new UUIPaginationEvent(UUIPaginationEvent.CHANGE));\n }\n\n /**\n * Change the page to a previous one.\n * @memberof UUIPaginationElement\n */\n goToPreviousPage() {\n this.current--;\n this.dispatchEvent(new UUIPaginationEvent(UUIPaginationEvent.CHANGE));\n }\n\n /**\n * Change the page to the one passed as an argument to this method.\n * @param {number} page\n * @memberof UUIPaginationElement\n */\n goToPage(page: number) {\n this.current = page;\n this.dispatchEvent(new UUIPaginationEvent(UUIPaginationEvent.CHANGE));\n }\n\n /** When having limited display of page-buttons and clicking a page-button that changes the current range, the focus stays on the position of the clicked button which is not anymore representing the number clicked, therefore we move focus to the button that represents the current page. */\n protected focusActivePage() {\n requestAnimationFrame(() => {\n // for none range changing clicks we need to ensure a rendering before querying.\n const activeButtonElement =\n this.renderRoot.querySelector<HTMLElement>('.active');\n if (activeButtonElement) {\n activeButtonElement.focus();\n }\n });\n }\n\n protected renderFirst() {\n return html`<uui-button\n compact\n class=\"nav\"\n label=${this.firstLabel}\n ?disabled=${this._current === 1}\n @click=${() => this.goToPage(1)}></uui-button>`;\n }\n\n protected renderPrevious() {\n return html`<uui-button\n compact\n class=\"nav\"\n label=${this.previousLabel}\n ?disabled=${this._current === 1}\n @click=${this.goToPreviousPage}></uui-button>`;\n }\n\n protected renderNext() {\n return html`<uui-button\n compact\n class=\"nav\"\n label=${this.nextLabel}\n ?disabled=${this._current === this.total}\n @click=${this.goToNextPage}></uui-button>`;\n }\n\n protected renderLast() {\n return html`\n <uui-button\n compact\n class=\"nav\"\n label=${this.lastLabel}\n ?disabled=${this.total === this._current}\n @click=${() => this.goToPage(this.total)}></uui-button>\n `;\n }\n\n protected renderDots() {\n return html`<uui-button\n compact\n look=\"outline\"\n role=\"listitem\"\n tabindex=\"-1\"\n class=\"dots\"\n label=\"More pages\"\n >...</uui-button\n >`;\n }\n\n protected renderPage(page: number) {\n return html`<uui-button\n compact\n look=\"outline\"\n role=\"listitem\"\n label=\"Go to page ${page}\"\n class=${'page' + (page === this._current ? ' active' : '')}\n tabindex=${page === this._current ? '-1' : ''}\n @click=${() => {\n if (page === this._current) return;\n this.goToPage(page);\n this.focusActivePage();\n }}>\n ${page}\n </uui-button>`;\n }\n\n protected renderLeftDots() {\n return html` ${this._visiblePages.includes(1) ? '' : this.renderDots()}`;\n }\n protected renderRightDots() {\n return html`${this._visiblePages.includes(this.total)\n ? ''\n : this.renderDots()}`;\n }\n\n protected renderNavigationLeft() {\n return html` ${this.renderFirst()} ${this.renderPrevious()}`;\n }\n protected renderNavigationRight() {\n return html` ${this.renderNext()} ${this.renderLast()}`;\n }\n\n render() {\n // prettier-ignore\n return html`\n ${this.renderNavigationLeft()}\n <uui-button-group role=\"list\" id=\"pages\">\n ${this.renderLeftDots()}\n ${this._visiblePages.map(\n page =>\n this.renderPage(page)\n )}\n ${this.renderRightDots()}\n </uui-button-group>\n ${this.renderNavigationRight()}\n `;\n }\n\n static override readonly styles = [\n css`\n :host {\n display: inline-flex;\n width: 100%;\n gap: 1px;\n }\n uui-button-group {\n flex-grow: 1;\n }\n\n uui-button-group uui-button {\n --uui-button-border-color: var(--uui-color-border-standalone);\n --uui-button-border-color-hover: var(--uui-color-interactive-emphasis);\n --uui-button-border-color-disabled: var(--uui-color-border-standalone);\n }\n\n uui-button-group uui-button:hover {\n z-index: 1;\n }\n\n .page {\n min-width: 36px;\n max-width: 72px;\n }\n .page.active {\n z-index: 1;\n }\n\n .nav {\n min-width: 72px;\n }\n\n .dots {\n pointer-events: none;\n min-width: 36px;\n max-width: 72px;\n }\n\n .active {\n pointer-events: none;\n --uui-button-font-weight: 700;\n --uui-button-contrast: var(--uui-color-selected);\n --uui-button-border-color: var(--uui-color-selected);\n --uui-button-border-width: 2px;\n }\n `,\n ];\n}\n"],"names":[],"mappings":"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"}
|
|
1
|
+
{"version":3,"file":"pagination.element.js","sources":["../../../src/components/pagination/pagination.element.ts"],"sourcesContent":["import type { UUIButtonElement } from '../button/button.js';\nimport { css, html, LitElement } from 'lit';\nimport { property, query, queryAll, state } from 'lit/decorators.js';\n\nimport { UUIPaginationEvent } from './UUIPaginationEvent.js';\n\nimport '../button/button.js';\nimport '../button-group/button-group.js';\n\n//this is how wide the button gets when it has 3 digits inside.\nconst PAGE_BUTTON_MAX_WIDTH = 45;\n\nconst limit = (val: number, min: number, max: number) => {\n return Math.min(Math.max(val, min), max);\n};\n\nconst arrayOfNumbers = (start: number, stop: number) => {\n return Array.from({ length: stop - start + 1 }, (_, i) => start + i);\n};\n\n/**\n * @element uui-pagination\n * @description Jump to a certain page and navigate to the next, last, previous or first page. The amount of visible page-buttons are adjusted to the available space.\n * @fires change - When clicked on the page button fires change event\n */\nexport class UUIPaginationElement extends LitElement {\n private readonly _observer = new ResizeObserver(\n this._calculateRange.bind(this),\n );\n\n connectedCallback() {\n super.connectedCallback();\n if (!this.hasAttribute('role')) this.setAttribute('role', 'navigation');\n this._visiblePages = this._generateVisiblePages(this.current);\n }\n\n disconnectedCallback() {\n this._observer.disconnect();\n }\n\n firstUpdated() {\n this._observer.observe(this._pagesGroup);\n\n this.updateLabel();\n this._calculateRange();\n }\n\n willUpdate(changedProperties: Map<string | number | symbol, unknown>) {\n if (changedProperties.has('current') || changedProperties.has('label')) {\n this.updateLabel();\n }\n }\n\n protected updateLabel() {\n this.ariaLabel = `${this.label || 'Pagination navigation'}. Current page: ${\n this.current\n }.`;\n }\n\n private _calculateRange() {\n const containerWidth = this.offsetWidth;\n\n // get all the buttons with .nav-button class and sum up their widths\n const navButtonsWidth = Array.from(this._navButtons).reduce(\n (totalWidth, button) => {\n return totalWidth + button.getBoundingClientRect().width;\n },\n 0,\n );\n\n // subtract width of nav-buttons from the pagination container\n const rangeBaseWidth = containerWidth - navButtonsWidth;\n\n // divide remaining width by max-width of page button (when it has 3 digits), then divide by 2 to get the range.\n // Range is number of buttons visible on either \"side\" of current pag button. So, if range === 5 we shall see 11 buttons in total - 5 before the current page and 5 after. This is why we divide by 2.\n const range = rangeBaseWidth / PAGE_BUTTON_MAX_WIDTH / 2;\n this._range = Math.max(0, Math.floor(range));\n this._visiblePages = this._generateVisiblePages(this.current);\n }\n\n private _generateVisiblePages(current: number) {\n let start: number;\n if (current < this._range) {\n start = 1;\n } else if (current < this.total - this._range) {\n start = current - this._range;\n } else {\n start = this.total - this._range * 2;\n }\n\n let stop: number;\n if (current <= this._range) {\n stop = this._range * 2 + 1;\n } else if (current < this.total - this._range) {\n stop = current + this._range;\n } else {\n stop = this.total;\n }\n\n const pages = arrayOfNumbers(\n limit(start, 1, this.total),\n limit(stop, 1, this.total),\n );\n\n return pages;\n }\n\n @queryAll('uui-button.nav')\n private readonly _navButtons!: Array<UUIButtonElement>;\n\n @query('#pages')\n private readonly _pagesGroup!: any;\n\n /**\n * This property is used to generate a proper `aria-label`. It will be announced by screen reader as: \"<<this.label>>. Current page: <<this.current>>\"\n * @type {string}\n * @attr\n */\n @property()\n label = '';\n\n /**\n * With this property you can overwrite aria-label.\n * @type {string}\n * @attr\n */\n @property({ reflect: true, attribute: 'aria-label' })\n ariaLabel = '';\n\n /**\n * This property is used to generate the name of the first button\n * @type {string}\n * @attr\n */\n @property()\n firstLabel: string = 'First';\n\n /**\n * This property is used to generate the name of the previous button\n * @type {string}\n * @attr\n */\n @property()\n previousLabel: string = 'Previous';\n\n /**\n * This property is used to generate the name of the next button\n * @type {string}\n * @attr\n */\n @property()\n nextLabel: string = 'Next';\n /**\n * This property is used to generate the name of the last button\n * @type {string}\n * @attr\n */\n @property()\n lastLabel: string = 'Last';\n\n private _total = 100;\n\n /**\n * Set the amount of pages to navigate.\n * @type {number}\n * @attr\n * @default: 1\n */\n @property({ type: Number })\n get total() {\n return this._total;\n }\n set total(newValue: number) {\n this._total = newValue;\n this._visiblePages = this._generateVisiblePages(this._current);\n this.requestUpdate('total', newValue);\n }\n\n @state()\n private _range = 0;\n\n @state()\n private _visiblePages: number[] = [];\n\n private _current = 1;\n\n /**\n * Define the current active page.\n * @type {number}\n * @attr\n */\n @property({ type: Number })\n get current() {\n return this._current;\n }\n set current(newValue: number) {\n const oldValue = this._current;\n this._current = limit(newValue, 1, this.total);\n this._visiblePages = this._generateVisiblePages(this._current);\n this.requestUpdate('current', oldValue);\n }\n\n /**\n * This method will change the page to a next one.\n * @memberof UUIPaginationElement\n */\n goToNextPage() {\n this.current++;\n this.dispatchEvent(new UUIPaginationEvent(UUIPaginationEvent.CHANGE));\n }\n\n /**\n * Change the page to a previous one.\n * @memberof UUIPaginationElement\n */\n goToPreviousPage() {\n this.current--;\n this.dispatchEvent(new UUIPaginationEvent(UUIPaginationEvent.CHANGE));\n }\n\n /**\n * Change the page to the one passed as an argument to this method.\n * @param {number} page\n * @memberof UUIPaginationElement\n */\n goToPage(page: number) {\n this.current = page;\n this.dispatchEvent(new UUIPaginationEvent(UUIPaginationEvent.CHANGE));\n }\n\n /** When having limited display of page-buttons and clicking a page-button that changes the current range, the focus stays on the position of the clicked button which is not anymore representing the number clicked, therefore we move focus to the button that represents the current page. */\n protected focusActivePage() {\n requestAnimationFrame(() => {\n // for none range changing clicks we need to ensure a rendering before querying.\n const activeButtonElement =\n this.renderRoot.querySelector<HTMLElement>('.active');\n if (activeButtonElement) {\n activeButtonElement.focus();\n }\n });\n }\n\n protected renderFirst() {\n return html`<uui-button\n compact\n class=\"nav\"\n label=${this.firstLabel}\n ?disabled=${this._current === 1}\n @click=${() => this.goToPage(1)}></uui-button>`;\n }\n\n protected renderPrevious() {\n return html`<uui-button\n compact\n class=\"nav\"\n label=${this.previousLabel}\n ?disabled=${this._current === 1}\n @click=${this.goToPreviousPage}></uui-button>`;\n }\n\n protected renderNext() {\n return html`<uui-button\n compact\n class=\"nav\"\n label=${this.nextLabel}\n ?disabled=${this._current === this.total}\n @click=${this.goToNextPage}></uui-button>`;\n }\n\n protected renderLast() {\n return html`\n <uui-button\n compact\n class=\"nav\"\n label=${this.lastLabel}\n ?disabled=${this.total === this._current}\n @click=${() => this.goToPage(this.total)}></uui-button>\n `;\n }\n\n protected renderDots() {\n return html`<uui-button\n compact\n look=\"outline\"\n role=\"listitem\"\n tabindex=\"-1\"\n class=\"dots\"\n label=\"More pages\"\n >...</uui-button\n >`;\n }\n\n protected renderPage(page: number) {\n return html`<uui-button\n compact\n look=\"outline\"\n role=\"listitem\"\n label=\"Go to page ${page}\"\n class=${'page' + (page === this._current ? ' active' : '')}\n tabindex=${page === this._current ? '-1' : ''}\n @click=${() => {\n if (page === this._current) return;\n this.goToPage(page);\n this.focusActivePage();\n }}>\n ${page}\n </uui-button>`;\n }\n\n protected renderLeftDots() {\n return html` ${this._visiblePages.includes(1) ? '' : this.renderDots()}`;\n }\n protected renderRightDots() {\n return html`${this._visiblePages.includes(this.total)\n ? ''\n : this.renderDots()}`;\n }\n\n protected renderNavigationLeft() {\n return html` ${this.renderFirst()} ${this.renderPrevious()}`;\n }\n protected renderNavigationRight() {\n return html` ${this.renderNext()} ${this.renderLast()}`;\n }\n\n render() {\n // prettier-ignore\n return html`\n ${this.renderNavigationLeft()}\n <uui-button-group role=\"list\" id=\"pages\">\n ${this.renderLeftDots()}\n ${this._visiblePages.map(\n page =>\n this.renderPage(page)\n )}\n ${this.renderRightDots()}\n </uui-button-group>\n ${this.renderNavigationRight()}\n `;\n }\n\n static override readonly styles = [\n css`\n :host {\n display: inline-flex;\n width: 100%;\n gap: 1px;\n }\n uui-button-group {\n flex-grow: 1;\n justify-content: center;\n }\n\n uui-button-group uui-button {\n --uui-button-border-color: var(--uui-color-border-standalone);\n --uui-button-border-color-hover: var(--uui-color-interactive-emphasis);\n --uui-button-border-color-disabled: var(--uui-color-border-standalone);\n }\n\n uui-button-group uui-button:hover {\n z-index: 1;\n }\n\n .page {\n min-width: 36px;\n max-width: 72px;\n }\n .page.active {\n z-index: 1;\n }\n\n .nav {\n min-width: 72px;\n }\n\n .dots {\n pointer-events: none;\n min-width: 36px;\n max-width: 72px;\n }\n\n .active {\n pointer-events: none;\n --uui-button-font-weight: 700;\n --uui-button-contrast: var(--uui-color-selected);\n --uui-button-border-color: var(--uui-color-selected);\n --uui-button-border-width: 2px;\n }\n `,\n ];\n}\n"],"names":[],"mappings":"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"}
|
|
@@ -0,0 +1,26 @@
|
|
|
1
|
+
import { LitElement } from 'lit';
|
|
2
|
+
declare class UUIPopoverContainerScrollLevelElement extends LitElement {
|
|
3
|
+
render(): import("lit-html").TemplateResult<1>;
|
|
4
|
+
}
|
|
5
|
+
/**
|
|
6
|
+
* Outermost scroll level — blue outline.
|
|
7
|
+
* @element uui-popover-container-scroll-level-1
|
|
8
|
+
*/
|
|
9
|
+
export declare class UUIPopoverContainerScrollLevel1Element extends UUIPopoverContainerScrollLevelElement {
|
|
10
|
+
static readonly styles: import("lit").CSSResult;
|
|
11
|
+
}
|
|
12
|
+
/**
|
|
13
|
+
* Middle scroll level — orange outline.
|
|
14
|
+
* @element uui-popover-container-scroll-level-2
|
|
15
|
+
*/
|
|
16
|
+
export declare class UUIPopoverContainerScrollLevel2Element extends UUIPopoverContainerScrollLevelElement {
|
|
17
|
+
static readonly styles: import("lit").CSSResult;
|
|
18
|
+
}
|
|
19
|
+
/**
|
|
20
|
+
* Innermost scroll level — green outline.
|
|
21
|
+
* @element uui-popover-container-scroll-level-3
|
|
22
|
+
*/
|
|
23
|
+
export declare class UUIPopoverContainerScrollLevel3Element extends UUIPopoverContainerScrollLevelElement {
|
|
24
|
+
static readonly styles: import("lit").CSSResult;
|
|
25
|
+
}
|
|
26
|
+
export {};
|
|
@@ -1,4 +1,5 @@
|
|
|
1
1
|
import { LitElement } from 'lit';
|
|
2
|
+
import '../scroll-container/scroll-container.js';
|
|
2
3
|
export type PopoverContainerPlacement = 'top' | 'top-start' | 'top-end' | 'bottom' | 'bottom-start' | 'bottom-end' | 'right' | 'right-start' | 'right-end' | 'left' | 'left-start' | 'left-end';
|
|
3
4
|
/**
|
|
4
5
|
* @element uui-popover-container
|
|
@@ -9,6 +9,7 @@ var __privateMethod = (obj, member, method) => (__accessCheck(obj, member, "acce
|
|
|
9
9
|
var _targetElement, _scrollParents, _sizeObserver, _size, _onBeforeToggle, _initUpdate, _updatePosition, _UUIPopoverContainerElement_instances, calculateAlignedPosition_fn, clampAndFlip_fn, _updatePadding, flipPlacement_fn, startScrollListener_fn, stopScrollListener_fn, calculateScrollParents_fn, getAncestorElement_fn;
|
|
10
10
|
import { LitElement, html, css } from "lit";
|
|
11
11
|
import { property, state } from "lit/decorators.js";
|
|
12
|
+
import "../scroll-container/scroll-container.js";
|
|
12
13
|
import { findAncestorByAttributeValue } from "../../internal/utils/findAncestorByAttributeValue.js";
|
|
13
14
|
var __defProp = Object.defineProperty;
|
|
14
15
|
var __getOwnPropDesc = Object.getOwnPropertyDescriptor;
|
|
@@ -62,6 +63,7 @@ const _UUIPopoverContainerElement = class _UUIPopoverContainerElement extends Li
|
|
|
62
63
|
});
|
|
63
64
|
} else {
|
|
64
65
|
__privateMethod(this, _UUIPopoverContainerElement_instances, stopScrollListener_fn).call(this);
|
|
66
|
+
this.style.removeProperty("--_available-height");
|
|
65
67
|
}
|
|
66
68
|
});
|
|
67
69
|
__privateSet(this, _initUpdate, () => {
|
|
@@ -86,7 +88,22 @@ const _UUIPopoverContainerElement = class _UUIPopoverContainerElement extends Li
|
|
|
86
88
|
const isCompletelyOutsideScreen = top + popoverRect.height < 0 || top > screenHeight || left + popoverRect.width < 0 || left > screenWidth;
|
|
87
89
|
if (isCompletelyOutsideScreen) {
|
|
88
90
|
this.hidePopover();
|
|
91
|
+
return;
|
|
89
92
|
}
|
|
93
|
+
const isTopPlacement = this._actualPlacement.startsWith("top");
|
|
94
|
+
const isBottomPlacement = this._actualPlacement.startsWith("bottom");
|
|
95
|
+
let availableHeight;
|
|
96
|
+
if (isTopPlacement) {
|
|
97
|
+
availableHeight = targetRect.top - 2 * this.margin;
|
|
98
|
+
} else if (isBottomPlacement) {
|
|
99
|
+
availableHeight = screenHeight - (targetRect.top + targetRect.height) - 2 * this.margin;
|
|
100
|
+
} else {
|
|
101
|
+
availableHeight = screenHeight - targetRect.top - this.margin;
|
|
102
|
+
}
|
|
103
|
+
this.style.setProperty(
|
|
104
|
+
"--_available-height",
|
|
105
|
+
`${Math.max(availableHeight, 0)}px`
|
|
106
|
+
);
|
|
90
107
|
this.style.transform = `translate(${left}px, ${top}px)`;
|
|
91
108
|
this.style.opacity = "1";
|
|
92
109
|
});
|
|
@@ -100,9 +117,9 @@ const _UUIPopoverContainerElement = class _UUIPopoverContainerElement extends Li
|
|
|
100
117
|
let side = this._actualPlacement.split("-")[0];
|
|
101
118
|
side = oppositeSides[side] || side;
|
|
102
119
|
side = side.charAt(0).toUpperCase() + side.slice(1);
|
|
103
|
-
const
|
|
104
|
-
this.style.
|
|
105
|
-
this.style[
|
|
120
|
+
const marginSide = `margin${side}`;
|
|
121
|
+
this.style.margin = "0";
|
|
122
|
+
this.style[marginSide] = `${this.margin}px`;
|
|
106
123
|
});
|
|
107
124
|
this.addEventListener("beforetoggle", __privateGet(this, _onBeforeToggle), {
|
|
108
125
|
passive: true
|
|
@@ -151,7 +168,7 @@ const _UUIPopoverContainerElement = class _UUIPopoverContainerElement extends Li
|
|
|
151
168
|
return __privateGet(this, _scrollParents);
|
|
152
169
|
}
|
|
153
170
|
render() {
|
|
154
|
-
return html`<slot></slot>`;
|
|
171
|
+
return html`<uui-scroll-container><slot></slot></uui-scroll-container>`;
|
|
155
172
|
}
|
|
156
173
|
};
|
|
157
174
|
_targetElement = new WeakMap();
|
|
@@ -283,6 +300,9 @@ calculateScrollParents_fn = function() {
|
|
|
283
300
|
__privateGet(this, _scrollParents).push(document.body);
|
|
284
301
|
};
|
|
285
302
|
getAncestorElement_fn = function(el) {
|
|
303
|
+
if (el?.assignedSlot) {
|
|
304
|
+
return el.assignedSlot;
|
|
305
|
+
}
|
|
286
306
|
if (el?.parentElement) {
|
|
287
307
|
return el.parentElement;
|
|
288
308
|
}
|
|
@@ -295,12 +315,16 @@ _UUIPopoverContainerElement.styles = [
|
|
|
295
315
|
width: fit-content;
|
|
296
316
|
height: fit-content;
|
|
297
317
|
border: none;
|
|
298
|
-
border-radius: 0;
|
|
299
318
|
padding: 0;
|
|
300
319
|
background-color: none;
|
|
301
320
|
background: none;
|
|
302
|
-
overflow: visible;
|
|
303
321
|
color: var(--uui-color-text);
|
|
322
|
+
box-shadow: var(--uui-shadow-depth-4);
|
|
323
|
+
border-radius: var(--uui-border-radius);
|
|
324
|
+
}
|
|
325
|
+
|
|
326
|
+
uui-scroll-container {
|
|
327
|
+
max-height: var(--_available-height, none);
|
|
304
328
|
}
|
|
305
329
|
`
|
|
306
330
|
];
|
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"popover-container.element.js","sources":["../../../src/components/popover-container/popover-container.element.ts"],"sourcesContent":["import { findAncestorByAttributeValue } from '../../internal/utils/index.js';\nimport { css, html, LitElement } from 'lit';\nimport { property, state } from 'lit/decorators.js';\n\nexport type PopoverContainerPlacement =\n | 'top'\n | 'top-start'\n | 'top-end'\n | 'bottom'\n | 'bottom-start'\n | 'bottom-end'\n | 'right'\n | 'right-start'\n | 'right-end'\n | 'left'\n | 'left-start'\n | 'left-end';\n\n/**\n * @element uui-popover-container\n * @attr popover - Indicates that the element is a popover container\n */\nexport class UUIPopoverContainerElement extends LitElement {\n /**\n * Set the distance between popover container element and target element.\n * @type {number}\n * @attr margin\n * @default 0\n */\n @property({ type: Number })\n margin = 0;\n\n /**\n * Read-only attribute to check if the popover is open\n * @type {boolean}\n * @readonly\n * @attr open\n * @default false\n */\n @property({ type: Boolean })\n get open() {\n return this._open;\n }\n\n /**\n * Define the placement of the popover container.\n * @attr placement\n * @default 'bottom-start'\n */\n @property({ type: String, reflect: true })\n get placement(): PopoverContainerPlacement {\n return this._placement;\n }\n set placement(newValue: PopoverContainerPlacement) {\n this._placement = newValue;\n this._actualPlacement = newValue;\n this.#initUpdate();\n }\n\n @state()\n _placement: PopoverContainerPlacement = 'bottom-start';\n\n @state()\n _open: boolean = false;\n\n @state()\n _actualPlacement: PopoverContainerPlacement = this._placement;\n\n #targetElement: HTMLElement | null = null;\n #scrollParents: Element[] = [];\n #sizeObserver: ResizeObserver | null = null;\n #size: { width: number; height: number } = { width: 0, height: 0 };\n\n constructor() {\n super();\n\n this.addEventListener('beforetoggle', this.#onBeforeToggle, {\n passive: true,\n });\n }\n\n connectedCallback(): void {\n super.connectedCallback();\n if (!this.hasAttribute('popover')) {\n this.setAttribute('popover', '');\n }\n\n if (!this.#sizeObserver) {\n this.#sizeObserver = new ResizeObserver(entries => {\n const element = entries[0]; // should be only one\n const width = element.contentRect.width;\n const height = element.contentRect.height;\n\n if (width === this.#size.width && height === this.#size.height) {\n return; // no change\n }\n\n this.#size = { width, height };\n this.#initUpdate();\n });\n\n // start listening for size changes\n this.#sizeObserver.observe(this);\n }\n }\n\n disconnectedCallback(): void {\n super.disconnectedCallback();\n this.#stopScrollListener();\n this.#sizeObserver?.disconnect();\n this.#sizeObserver = null;\n }\n\n readonly #onBeforeToggle = (event: any) => {\n this._open = event.newState === 'open';\n\n this.#targetElement = findAncestorByAttributeValue(\n this,\n 'popovertarget',\n this.id,\n );\n\n // Dispatch a custom event that can be listened to by the popover target.\n // Mostly used for UUIButton.\n this.#targetElement?.dispatchEvent(\n new CustomEvent('uui-popover-before-toggle', {\n bubbles: false,\n composed: false,\n detail: { oldState: event.oldState, newState: event.newState },\n }),\n );\n\n if (this._open) {\n this.#calculateScrollParents();\n\n this.#startScrollListener();\n\n requestAnimationFrame(() => {\n this.#initUpdate();\n });\n } else {\n this.#stopScrollListener();\n }\n };\n\n readonly #initUpdate = () => {\n if (!this._open) return;\n\n this._actualPlacement = this._placement;\n this.style.opacity = '0';\n\n // 3 iterations makes the popover flip back to the initial position if theres no space for it on either side.\n this.#updatePosition(3);\n };\n\n readonly #updatePosition = (iteration: number) => {\n this.#updatePadding();\n\n // Iterations makes sure that we don't overflow the stack.\n // That could happen if the is no space for the popover on either side, which without iterations, would make it flip back and forth until the stack overflows\n iteration--;\n if (this.#targetElement === null) return;\n\n const targetRect = this.#targetElement.getBoundingClientRect();\n const popoverRect = this.getBoundingClientRect();\n\n let { top, left } = this.#calculateAlignedPosition(targetRect, popoverRect);\n const result = this.#clampAndFlip(\n top,\n left,\n targetRect,\n popoverRect,\n iteration,\n );\n\n if (result === null) return; // flipped and recursed\n\n top = result.top;\n left = result.left;\n\n // Detect if the popover is completely outside the screen on any side\n const screenWidth = window.innerWidth;\n const screenHeight = window.innerHeight;\n const isCompletelyOutsideScreen =\n top + popoverRect.height < 0 ||\n top > screenHeight ||\n left + popoverRect.width < 0 ||\n left > screenWidth;\n\n if (isCompletelyOutsideScreen) {\n this.hidePopover();\n }\n\n // Set the popover's position\n this.style.transform = `translate(${left}px, ${top}px)`;\n this.style.opacity = '1';\n };\n\n #calculateAlignedPosition(targetRect: DOMRect, popoverRect: DOMRect) {\n const isStart = this._actualPlacement.includes('-start');\n const isEnd = this._actualPlacement.includes('-end');\n\n // Alignment along the cross-axis\n const align = (pos: number, targetSize: number, popoverSize: number) => {\n if (isStart) return pos;\n if (isEnd) return pos + targetSize - popoverSize;\n return pos + targetSize / 2 - popoverSize / 2;\n };\n\n const side = this._actualPlacement.split('-')[0];\n\n // For top/bottom: top is determined by placement, left by alignment\n // For left/right: left is determined by placement, top by alignment\n const positions: Record<string, { top: number; left: number }> = {\n bottom: {\n top: targetRect.top + targetRect.height,\n left: align(targetRect.left, targetRect.width, popoverRect.width),\n },\n top: {\n top: targetRect.top - popoverRect.height,\n left: align(targetRect.left, targetRect.width, popoverRect.width),\n },\n left: {\n top: align(targetRect.top, targetRect.height, popoverRect.height),\n left: targetRect.left - popoverRect.width,\n },\n right: {\n top: align(targetRect.top, targetRect.height, popoverRect.height),\n left: targetRect.left + targetRect.width,\n },\n };\n\n return positions[side] ?? { top: 0, left: 0 };\n }\n\n #clampAndFlip(\n top: number,\n left: number,\n targetRect: DOMRect,\n popoverRect: DOMRect,\n iteration: number,\n ): { top: number; left: number } | null {\n const screenWidth = window.innerWidth;\n const screenHeight = window.innerHeight;\n const side = this._actualPlacement.split('-')[0];\n const isVertical = side === 'top' || side === 'bottom';\n\n // Vertical clamping\n const topTargetVsScreenTop = Math.min(\n 0,\n targetRect.top + targetRect.height,\n );\n const topTargetVsScreenBottom = Math.max(\n Math.min(top, screenHeight - popoverRect.height),\n targetRect.top - popoverRect.height,\n );\n const topClamped = Math.max(topTargetVsScreenTop, topTargetVsScreenBottom);\n\n if (topClamped !== top && isVertical && iteration > 0) {\n this.#flipPlacement();\n this.#updatePosition(iteration);\n return null;\n }\n\n // Horizontal clamping\n const leftTargetVsScreenLeft = Math.min(\n 0,\n targetRect.left + targetRect.width,\n );\n const leftTargetVsScreenRight = Math.max(\n Math.min(left, screenWidth - popoverRect.width),\n targetRect.left - popoverRect.width,\n );\n const leftClamped = Math.max(\n leftTargetVsScreenLeft,\n leftTargetVsScreenRight,\n );\n\n if (leftClamped !== left && !isVertical && iteration > 0) {\n this.#flipPlacement();\n this.#updatePosition(iteration);\n return null;\n }\n\n return { top: topClamped, left: leftClamped };\n }\n\n readonly #updatePadding = () => {\n const oppositeSides: Record<string, string> = {\n top: 'bottom',\n bottom: 'top',\n left: 'right',\n right: 'left',\n };\n\n // find the side excluding start/end\n let side = this._actualPlacement.split('-')[0];\n // find the opposite side\n side = oppositeSides[side] || side;\n // capitalize the side\n side = side.charAt(0).toUpperCase() + side.slice(1);\n\n const paddingSide = `padding${side}`;\n this.style.padding = '0';\n (this.style as any)[paddingSide] = `${this.margin}px`;\n };\n\n #flipPlacement() {\n const [direction, position] = this._actualPlacement.split('-');\n const opposites: Record<string, string> = {\n top: 'bottom',\n bottom: 'top',\n left: 'right',\n right: 'left',\n };\n const oppositeDirection = opposites[direction] ?? direction;\n this._actualPlacement =\n `${oppositeDirection}-${position}` as PopoverContainerPlacement;\n }\n\n #startScrollListener() {\n this.#scrollParents.forEach(el => {\n el.addEventListener('scroll', this.#initUpdate, { passive: true });\n });\n document.addEventListener('scroll', this.#initUpdate, { passive: true });\n }\n #stopScrollListener() {\n this.#scrollParents.forEach(el => {\n el.removeEventListener('scroll', this.#initUpdate);\n });\n document.removeEventListener('scroll', this.#initUpdate);\n }\n\n /**\n * @internal\n */\n _getScrollParents() {\n return this.#scrollParents;\n }\n\n #calculateScrollParents(): void {\n // Clear previous scroll parents to avoid duplicates\n this.#scrollParents = [];\n\n if (!this.#targetElement) return;\n\n let style = getComputedStyle(this.#targetElement);\n if (style.position === 'fixed') {\n return;\n }\n\n const includeHidden = false;\n let excludeStaticParent = style.position === 'absolute';\n const overflowRegex = includeHidden\n ? /(auto|scroll|hidden)/\n : /(auto|scroll)/;\n\n let el: HTMLElement | undefined | null = this.#targetElement;\n while (el) {\n style = getComputedStyle(el);\n\n if (excludeStaticParent && style.position === 'static') {\n el = this.#getAncestorElement(el);\n continue;\n }\n\n if (style.position !== 'static') {\n excludeStaticParent = style.position === 'absolute';\n }\n\n if (\n overflowRegex.test(style.overflow + style.overflowY + style.overflowX)\n ) {\n this.#scrollParents.push(el);\n }\n if (style.position === 'fixed') {\n return;\n }\n\n el = this.#getAncestorElement(el);\n }\n this.#scrollParents.push(document.body);\n }\n\n #getAncestorElement(el: HTMLElement | null): HTMLElement | null {\n if (el?.parentElement) {\n return el.parentElement;\n }\n\n // If we had no parentElement, then check for shadow roots:\n return (el?.getRootNode() as any)?.host;\n }\n\n render() {\n return html`<slot></slot>`;\n }\n\n static override readonly styles = [\n css`\n :host {\n margin: 0;\n width: fit-content;\n height: fit-content;\n border: none;\n border-radius: 0;\n padding: 0;\n background-color: none;\n background: none;\n overflow: visible;\n color: var(--uui-color-text);\n }\n `,\n ];\n}\n"],"names":[],"mappings":"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"}
|
|
1
|
+
{"version":3,"file":"popover-container.element.js","sources":["../../../src/components/popover-container/popover-container.element.ts"],"sourcesContent":["import { findAncestorByAttributeValue } from '../../internal/utils/index.js';\nimport { css, html, LitElement } from 'lit';\nimport { property, state } from 'lit/decorators.js';\n\nimport '../scroll-container/scroll-container.js';\n\nexport type PopoverContainerPlacement =\n | 'top'\n | 'top-start'\n | 'top-end'\n | 'bottom'\n | 'bottom-start'\n | 'bottom-end'\n | 'right'\n | 'right-start'\n | 'right-end'\n | 'left'\n | 'left-start'\n | 'left-end';\n\n/**\n * @element uui-popover-container\n * @attr popover - Indicates that the element is a popover container\n */\nexport class UUIPopoverContainerElement extends LitElement {\n /**\n * Set the distance between popover container element and target element.\n * @type {number}\n * @attr margin\n * @default 0\n */\n @property({ type: Number })\n margin = 0;\n\n /**\n * Read-only attribute to check if the popover is open\n * @type {boolean}\n * @readonly\n * @attr open\n * @default false\n */\n @property({ type: Boolean })\n get open() {\n return this._open;\n }\n\n /**\n * Define the placement of the popover container.\n * @attr placement\n * @default 'bottom-start'\n */\n @property({ type: String, reflect: true })\n get placement(): PopoverContainerPlacement {\n return this._placement;\n }\n set placement(newValue: PopoverContainerPlacement) {\n this._placement = newValue;\n this._actualPlacement = newValue;\n this.#initUpdate();\n }\n\n @state()\n _placement: PopoverContainerPlacement = 'bottom-start';\n\n @state()\n _open: boolean = false;\n\n @state()\n _actualPlacement: PopoverContainerPlacement = this._placement;\n\n #targetElement: HTMLElement | null = null;\n #scrollParents: Element[] = [];\n #sizeObserver: ResizeObserver | null = null;\n #size: { width: number; height: number } = { width: 0, height: 0 };\n\n constructor() {\n super();\n\n this.addEventListener('beforetoggle', this.#onBeforeToggle, {\n passive: true,\n });\n }\n\n connectedCallback(): void {\n super.connectedCallback();\n if (!this.hasAttribute('popover')) {\n this.setAttribute('popover', '');\n }\n\n if (!this.#sizeObserver) {\n this.#sizeObserver = new ResizeObserver(entries => {\n const element = entries[0]; // should be only one\n const width = element.contentRect.width;\n const height = element.contentRect.height;\n\n if (width === this.#size.width && height === this.#size.height) {\n return; // no change\n }\n\n this.#size = { width, height };\n this.#initUpdate();\n });\n\n // start listening for size changes\n this.#sizeObserver.observe(this);\n }\n }\n\n disconnectedCallback(): void {\n super.disconnectedCallback();\n this.#stopScrollListener();\n this.#sizeObserver?.disconnect();\n this.#sizeObserver = null;\n }\n\n readonly #onBeforeToggle = (event: any) => {\n this._open = event.newState === 'open';\n\n this.#targetElement = findAncestorByAttributeValue(\n this,\n 'popovertarget',\n this.id,\n );\n\n // Dispatch a custom event that can be listened to by the popover target.\n // Mostly used for UUIButton.\n this.#targetElement?.dispatchEvent(\n new CustomEvent('uui-popover-before-toggle', {\n bubbles: false,\n composed: false,\n detail: { oldState: event.oldState, newState: event.newState },\n }),\n );\n\n if (this._open) {\n this.#calculateScrollParents();\n\n this.#startScrollListener();\n\n requestAnimationFrame(() => {\n this.#initUpdate();\n });\n } else {\n this.#stopScrollListener();\n this.style.removeProperty('--_available-height');\n }\n };\n\n readonly #initUpdate = () => {\n if (!this._open) return;\n\n this._actualPlacement = this._placement;\n this.style.opacity = '0';\n\n // 3 iterations makes the popover flip back to the initial position if theres no space for it on either side.\n this.#updatePosition(3);\n };\n\n readonly #updatePosition = (iteration: number) => {\n this.#updatePadding();\n\n // Iterations makes sure that we don't overflow the stack.\n // That could happen if the is no space for the popover on either side, which without iterations, would make it flip back and forth until the stack overflows\n iteration--;\n if (this.#targetElement === null) return;\n\n const targetRect = this.#targetElement.getBoundingClientRect();\n const popoverRect = this.getBoundingClientRect();\n\n let { top, left } = this.#calculateAlignedPosition(targetRect, popoverRect);\n const result = this.#clampAndFlip(\n top,\n left,\n targetRect,\n popoverRect,\n iteration,\n );\n\n if (result === null) return; // flipped and recursed\n\n top = result.top;\n left = result.left;\n\n // Detect if the popover is completely outside the screen on any side\n const screenWidth = window.innerWidth;\n const screenHeight = window.innerHeight;\n const isCompletelyOutsideScreen =\n top + popoverRect.height < 0 ||\n top > screenHeight ||\n left + popoverRect.width < 0 ||\n left > screenWidth;\n\n if (isCompletelyOutsideScreen) {\n this.hidePopover();\n return;\n }\n\n // Constrain the slot height to the available space in the popover's growth direction.\n const isTopPlacement = this._actualPlacement.startsWith('top');\n const isBottomPlacement = this._actualPlacement.startsWith('bottom');\n let availableHeight: number;\n if (isTopPlacement) {\n availableHeight = targetRect.top - 2 * this.margin;\n } else if (isBottomPlacement) {\n // margin once for the popover's own padding, once for a safe edge buffer\n availableHeight =\n screenHeight - (targetRect.top + targetRect.height) - 2 * this.margin;\n } else {\n availableHeight = screenHeight - targetRect.top - this.margin;\n }\n this.style.setProperty(\n '--_available-height',\n `${Math.max(availableHeight, 0)}px`,\n );\n\n // Set the popover's position\n this.style.transform = `translate(${left}px, ${top}px)`;\n this.style.opacity = '1';\n };\n\n #calculateAlignedPosition(targetRect: DOMRect, popoverRect: DOMRect) {\n const isStart = this._actualPlacement.includes('-start');\n const isEnd = this._actualPlacement.includes('-end');\n\n // Alignment along the cross-axis\n const align = (pos: number, targetSize: number, popoverSize: number) => {\n if (isStart) return pos;\n if (isEnd) return pos + targetSize - popoverSize;\n return pos + targetSize / 2 - popoverSize / 2;\n };\n\n const side = this._actualPlacement.split('-')[0];\n\n // For top/bottom: top is determined by placement, left by alignment\n // For left/right: left is determined by placement, top by alignment\n const positions: Record<string, { top: number; left: number }> = {\n bottom: {\n top: targetRect.top + targetRect.height,\n left: align(targetRect.left, targetRect.width, popoverRect.width),\n },\n top: {\n top: targetRect.top - popoverRect.height,\n left: align(targetRect.left, targetRect.width, popoverRect.width),\n },\n left: {\n top: align(targetRect.top, targetRect.height, popoverRect.height),\n left: targetRect.left - popoverRect.width,\n },\n right: {\n top: align(targetRect.top, targetRect.height, popoverRect.height),\n left: targetRect.left + targetRect.width,\n },\n };\n\n return positions[side] ?? { top: 0, left: 0 };\n }\n\n #clampAndFlip(\n top: number,\n left: number,\n targetRect: DOMRect,\n popoverRect: DOMRect,\n iteration: number,\n ): { top: number; left: number } | null {\n const screenWidth = window.innerWidth;\n const screenHeight = window.innerHeight;\n const side = this._actualPlacement.split('-')[0];\n const isVertical = side === 'top' || side === 'bottom';\n\n // Vertical clamping\n const topTargetVsScreenTop = Math.min(\n 0,\n targetRect.top + targetRect.height,\n );\n const topTargetVsScreenBottom = Math.max(\n Math.min(top, screenHeight - popoverRect.height),\n targetRect.top - popoverRect.height,\n );\n const topClamped = Math.max(topTargetVsScreenTop, topTargetVsScreenBottom);\n\n if (topClamped !== top && isVertical && iteration > 0) {\n this.#flipPlacement();\n this.#updatePosition(iteration);\n return null;\n }\n\n // Horizontal clamping\n const leftTargetVsScreenLeft = Math.min(\n 0,\n targetRect.left + targetRect.width,\n );\n const leftTargetVsScreenRight = Math.max(\n Math.min(left, screenWidth - popoverRect.width),\n targetRect.left - popoverRect.width,\n );\n const leftClamped = Math.max(\n leftTargetVsScreenLeft,\n leftTargetVsScreenRight,\n );\n\n if (leftClamped !== left && !isVertical && iteration > 0) {\n this.#flipPlacement();\n this.#updatePosition(iteration);\n return null;\n }\n\n return { top: topClamped, left: leftClamped };\n }\n\n readonly #updatePadding = () => {\n const oppositeSides: Record<string, string> = {\n top: 'bottom',\n bottom: 'top',\n left: 'right',\n right: 'left',\n };\n\n // find the side excluding start/end\n let side = this._actualPlacement.split('-')[0];\n // find the opposite side\n side = oppositeSides[side] || side;\n // capitalize the side\n side = side.charAt(0).toUpperCase() + side.slice(1);\n\n const marginSide = `margin${side}`;\n this.style.margin = '0';\n (this.style as any)[marginSide] = `${this.margin}px`;\n };\n\n #flipPlacement() {\n const [direction, position] = this._actualPlacement.split('-');\n const opposites: Record<string, string> = {\n top: 'bottom',\n bottom: 'top',\n left: 'right',\n right: 'left',\n };\n const oppositeDirection = opposites[direction] ?? direction;\n this._actualPlacement =\n `${oppositeDirection}-${position}` as PopoverContainerPlacement;\n }\n\n #startScrollListener() {\n this.#scrollParents.forEach(el => {\n el.addEventListener('scroll', this.#initUpdate, { passive: true });\n });\n document.addEventListener('scroll', this.#initUpdate, { passive: true });\n }\n #stopScrollListener() {\n this.#scrollParents.forEach(el => {\n el.removeEventListener('scroll', this.#initUpdate);\n });\n document.removeEventListener('scroll', this.#initUpdate);\n }\n\n /**\n * @internal\n */\n _getScrollParents() {\n return this.#scrollParents;\n }\n\n #calculateScrollParents(): void {\n // Clear previous scroll parents to avoid duplicates\n this.#scrollParents = [];\n\n if (!this.#targetElement) return;\n\n let style = getComputedStyle(this.#targetElement);\n if (style.position === 'fixed') {\n return;\n }\n\n const includeHidden = false;\n let excludeStaticParent = style.position === 'absolute';\n const overflowRegex = includeHidden\n ? /(auto|scroll|hidden)/\n : /(auto|scroll)/;\n\n let el: HTMLElement | undefined | null = this.#targetElement;\n while (el) {\n style = getComputedStyle(el);\n\n if (excludeStaticParent && style.position === 'static') {\n el = this.#getAncestorElement(el);\n continue;\n }\n\n if (style.position !== 'static') {\n excludeStaticParent = style.position === 'absolute';\n }\n\n if (\n overflowRegex.test(style.overflow + style.overflowY + style.overflowX)\n ) {\n this.#scrollParents.push(el);\n }\n if (style.position === 'fixed') {\n return;\n }\n\n el = this.#getAncestorElement(el);\n }\n this.#scrollParents.push(document.body);\n }\n\n #getAncestorElement(el: HTMLElement | null): HTMLElement | null {\n if (el?.assignedSlot) {\n return el.assignedSlot;\n }\n if (el?.parentElement) {\n return el.parentElement;\n }\n\n // If we had no parentElement, then check for shadow roots:\n return (el?.getRootNode() as any)?.host;\n }\n\n render() {\n return html`<uui-scroll-container><slot></slot></uui-scroll-container>`;\n }\n\n static override readonly styles = [\n css`\n :host {\n margin: 0;\n width: fit-content;\n height: fit-content;\n border: none;\n padding: 0;\n background-color: none;\n background: none;\n color: var(--uui-color-text);\n box-shadow: var(--uui-shadow-depth-4);\n border-radius: var(--uui-border-radius);\n }\n\n uui-scroll-container {\n max-height: var(--_available-height, none);\n }\n `,\n ];\n}\n"],"names":[],"mappings":"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"}
|
|
@@ -41,8 +41,8 @@ _UUITableRowElement.styles = [
|
|
|
41
41
|
:host {
|
|
42
42
|
display: table-row;
|
|
43
43
|
position: relative;
|
|
44
|
-
outline-offset: -
|
|
45
|
-
border-radius: var(--uui-border-radius);
|
|
44
|
+
outline-offset: -4px;
|
|
45
|
+
border-radius: var(--uui-border-radius-3);
|
|
46
46
|
}
|
|
47
47
|
|
|
48
48
|
:host([selectable]) {
|
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"table-row.element.js","sources":["../../../src/components/table/table-row.element.ts"],"sourcesContent":["import {\n SelectableMixin,\n SelectOnlyMixin,\n} from '../../internal/mixins/index.js';\nimport { css, html, LitElement } from 'lit';\nimport { queryAssignedElements } from 'lit/decorators.js';\n\n/**\n * Table row element with option to set is as selectable. Parent for uui-table-cell. Must be a child of uui-table.\n * @element uui-table-row\n * @slot for <uui-table-cell> elements that should be in the row.\n * @cssprop --uui-table-row-color-selected - overwrite the color of the selected row\n */\nexport class UUITableRowElement extends SelectOnlyMixin(\n SelectableMixin(LitElement),\n) {\n connectedCallback() {\n super.connectedCallback();\n this.setAttribute('role', 'row');\n }\n\n @queryAssignedElements({\n flatten: true,\n selector: 'uui-table-cell, [uui-table-cell], [role=cell]',\n })\n private readonly slotCellNodes?: unknown[];\n\n protected updated(changedProperties: Map<string | number | symbol, unknown>) {\n if (changedProperties.has('selectOnly')) {\n this.updateChildSelectOnly();\n }\n }\n\n private updateChildSelectOnly() {\n if (this.slotCellNodes) {\n this.slotCellNodes.forEach((el: any) => {\n if (el.disableChildInteraction !== undefined) {\n el.disableChildInteraction = this.selectOnly;\n }\n });\n }\n }\n\n render() {\n return html` <slot @slotchanged=${this.updateChildSelectOnly}></slot> `;\n }\n\n static override readonly styles = [\n css`\n :host {\n display: table-row;\n position: relative;\n outline-offset: -
|
|
1
|
+
{"version":3,"file":"table-row.element.js","sources":["../../../src/components/table/table-row.element.ts"],"sourcesContent":["import {\n SelectableMixin,\n SelectOnlyMixin,\n} from '../../internal/mixins/index.js';\nimport { css, html, LitElement } from 'lit';\nimport { queryAssignedElements } from 'lit/decorators.js';\n\n/**\n * Table row element with option to set is as selectable. Parent for uui-table-cell. Must be a child of uui-table.\n * @element uui-table-row\n * @slot for <uui-table-cell> elements that should be in the row.\n * @cssprop --uui-table-row-color-selected - overwrite the color of the selected row\n */\nexport class UUITableRowElement extends SelectOnlyMixin(\n SelectableMixin(LitElement),\n) {\n connectedCallback() {\n super.connectedCallback();\n this.setAttribute('role', 'row');\n }\n\n @queryAssignedElements({\n flatten: true,\n selector: 'uui-table-cell, [uui-table-cell], [role=cell]',\n })\n private readonly slotCellNodes?: unknown[];\n\n protected updated(changedProperties: Map<string | number | symbol, unknown>) {\n if (changedProperties.has('selectOnly')) {\n this.updateChildSelectOnly();\n }\n }\n\n private updateChildSelectOnly() {\n if (this.slotCellNodes) {\n this.slotCellNodes.forEach((el: any) => {\n if (el.disableChildInteraction !== undefined) {\n el.disableChildInteraction = this.selectOnly;\n }\n });\n }\n }\n\n render() {\n return html` <slot @slotchanged=${this.updateChildSelectOnly}></slot> `;\n }\n\n static override readonly styles = [\n css`\n :host {\n display: table-row;\n position: relative;\n outline-offset: -4px;\n border-radius: var(--uui-border-radius-3);\n }\n\n :host([selectable]) {\n cursor: pointer;\n }\n\n :host(:focus-visible) {\n outline: 2px solid var(--uui-color-focus);\n }\n :host([selected]) {\n outline: 2px solid\n var(--uui-table-row-color-selected, var(--uui-color-selected));\n }\n :host([selected]:focus) {\n outline-color: var(--uui-color-focus);\n }\n `,\n ];\n}\n"],"names":[],"mappings":";;;;;;;;;;;;;AAaO,MAAM,sBAAN,MAAM,4BAA2B;AAAA,EACtC,gBAAgB,UAAU;AAC5B,EAAE;AAAA,EACA,oBAAoB;AAClB,UAAM,kBAAA;AACN,SAAK,aAAa,QAAQ,KAAK;AAAA,EACjC;AAAA,EAQU,QAAQ,mBAA2D;AAC3E,QAAI,kBAAkB,IAAI,YAAY,GAAG;AACvC,WAAK,sBAAA;AAAA,IACP;AAAA,EACF;AAAA,EAEQ,wBAAwB;AAC9B,QAAI,KAAK,eAAe;AACtB,WAAK,cAAc,QAAQ,CAAC,OAAY;AACtC,YAAI,GAAG,4BAA4B,QAAW;AAC5C,aAAG,0BAA0B,KAAK;AAAA,QACpC;AAAA,MACF,CAAC;AAAA,IACH;AAAA,EACF;AAAA,EAEA,SAAS;AACP,WAAO,2BAA2B,KAAK,qBAAqB;AAAA,EAC9D;AA2BF;AAzBE,oBAAyB,SAAS;AAAA,EAChC;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAnCG,IAAM,qBAAN;AAYY,gBAAA;AAAA,EAJhB,sBAAsB;AAAA,IACrB,SAAS;AAAA,IACT,UAAU;AAAA,EAAA,CACX;AAAA,GAXU,mBAYM,WAAA,eAAA;"}
|
|
@@ -15,8 +15,8 @@ _UUITableElement.styles = [
|
|
|
15
15
|
display: table;
|
|
16
16
|
width: 100%;
|
|
17
17
|
background-color: var(--uui-color-surface);
|
|
18
|
-
cursor: default;
|
|
19
18
|
|
|
19
|
+
overflow: clip;
|
|
20
20
|
border-radius: var(--uui-border-radius-3);
|
|
21
21
|
border-width: var(--uui-box-border-width, 1px);
|
|
22
22
|
border-style: solid;
|
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"table.element.js","sources":["../../../src/components/table/table.element.ts"],"sourcesContent":["import { css, html, LitElement } from 'lit';\n\n/**\n * Recreation of native table and it's child elements. `<uui-table>` is a parent element to `<uui-table-head>` `<and uui-table-row>`. To make it fully accessible remember to add aria-label and aria-describedby.\n * @element uui-table\n * @slot - slot for `<uui-table-head>` and `<uui-table-row>` elements. Make a table out of them.\n */\nexport class UUITableElement extends LitElement {\n /* consider select-only attribute on this level? */\n\n connectedCallback() {\n super.connectedCallback();\n this.setAttribute('role', 'table');\n }\n\n render() {\n return html`<slot></slot>`;\n }\n\n static override readonly styles = [\n css`\n :host {\n display: table;\n width: 100%;\n background-color: var(--uui-color-surface);\n
|
|
1
|
+
{"version":3,"file":"table.element.js","sources":["../../../src/components/table/table.element.ts"],"sourcesContent":["import { css, html, LitElement } from 'lit';\n\n/**\n * Recreation of native table and it's child elements. `<uui-table>` is a parent element to `<uui-table-head>` `<and uui-table-row>`. To make it fully accessible remember to add aria-label and aria-describedby.\n * @element uui-table\n * @slot - slot for `<uui-table-head>` and `<uui-table-row>` elements. Make a table out of them.\n */\nexport class UUITableElement extends LitElement {\n /* consider select-only attribute on this level? */\n\n connectedCallback() {\n super.connectedCallback();\n this.setAttribute('role', 'table');\n }\n\n render() {\n return html`<slot></slot>`;\n }\n\n static override readonly styles = [\n css`\n :host {\n display: table;\n width: 100%;\n background-color: var(--uui-color-surface);\n\n overflow: clip;\n border-radius: var(--uui-border-radius-3);\n border-width: var(--uui-box-border-width, 1px);\n border-style: solid;\n border-color: var(--uui-color-divider-standalone);\n }\n `,\n ];\n}\n"],"names":[],"mappings":";AAOO,MAAM,mBAAN,MAAM,yBAAwB,WAAW;AAAA;AAAA,EAG9C,oBAAoB;AAClB,UAAM,kBAAA;AACN,SAAK,aAAa,QAAQ,OAAO;AAAA,EACnC;AAAA,EAEA,SAAS;AACP,WAAO;AAAA,EACT;AAiBF;AAfE,iBAAyB,SAAS;AAAA,EAChC;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAbG,IAAM,kBAAN;"}
|