@digital-realty/ix-radio 1.0.1
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/LICENSE +21 -0
- package/README.md +75 -0
- package/demo/index.html +41 -0
- package/demo/native.html +71 -0
- package/dist/src/IxRadio.d.ts +45 -0
- package/dist/src/IxRadio.js +147 -0
- package/dist/src/IxRadio.js.map +1 -0
- package/dist/src/index.d.ts +1 -0
- package/dist/src/index.js +2 -0
- package/dist/src/index.js.map +1 -0
- package/dist/src/ix-radio-styles.d.ts +1 -0
- package/dist/src/ix-radio-styles.js +3 -0
- package/dist/src/ix-radio-styles.js.map +1 -0
- package/dist/src/ix-radio.d.ts +1 -0
- package/dist/src/ix-radio.js +3 -0
- package/dist/src/ix-radio.js.map +1 -0
- package/dist/src/react/IxRadio.d.ts +5 -0
- package/dist/src/react/IxRadio.js +14 -0
- package/dist/src/react/IxRadio.js.map +1 -0
- package/dist/src/single-selection-controller.d.ts +80 -0
- package/dist/src/single-selection-controller.js +197 -0
- package/dist/src/single-selection-controller.js.map +1 -0
- package/dist/test/ix-radio.test.d.ts +1 -0
- package/dist/test/ix-radio.test.js +47 -0
- package/dist/test/ix-radio.test.js.map +1 -0
- package/dist/tsconfig.tsbuildinfo +1 -0
- package/package.json +96 -0
- package/src/IxRadio.ts +153 -0
- package/src/index.ts +1 -0
- package/src/ix-radio-styles.ts +3 -0
- package/src/ix-radio.ts +3 -0
- package/src/react/IxRadio.ts +15 -0
- package/src/single-selection-controller.ts +231 -0
- package/test/ix-radio.test.ts +50 -0
- package/tsconfig.json +21 -0
- package/web-dev-server.config.mjs +27 -0
- package/web-test-runner.config.mjs +41 -0
package/LICENSE
ADDED
|
@@ -0,0 +1,21 @@
|
|
|
1
|
+
MIT License
|
|
2
|
+
|
|
3
|
+
Copyright (c) 2023 ix-radio
|
|
4
|
+
|
|
5
|
+
Permission is hereby granted, free of charge, to any person obtaining a copy
|
|
6
|
+
of this software and associated documentation files (the "Software"), to deal
|
|
7
|
+
in the Software without restriction, including without limitation the rights
|
|
8
|
+
to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
|
|
9
|
+
copies of the Software, and to permit persons to whom the Software is
|
|
10
|
+
furnished to do so, subject to the following conditions:
|
|
11
|
+
|
|
12
|
+
The above copyright notice and this permission notice shall be included in all
|
|
13
|
+
copies or substantial portions of the Software.
|
|
14
|
+
|
|
15
|
+
THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
|
|
16
|
+
IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
|
|
17
|
+
FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
|
|
18
|
+
AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
|
|
19
|
+
LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
|
|
20
|
+
OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
|
|
21
|
+
SOFTWARE.
|
package/README.md
ADDED
|
@@ -0,0 +1,75 @@
|
|
|
1
|
+
# \<ix-radio>
|
|
2
|
+
|
|
3
|
+
This webcomponent follows the [open-wc](https://github.com/open-wc/open-wc) recommendation.
|
|
4
|
+
|
|
5
|
+
## Installation
|
|
6
|
+
|
|
7
|
+
```bash
|
|
8
|
+
npm i @digital-realty/ix-radio
|
|
9
|
+
```
|
|
10
|
+
|
|
11
|
+
## Usage
|
|
12
|
+
|
|
13
|
+
```html
|
|
14
|
+
<script type="module">
|
|
15
|
+
import '@digital-realty/ix-radio/ix-radio.js';
|
|
16
|
+
</script>
|
|
17
|
+
|
|
18
|
+
<ix-radio></ix-radio>
|
|
19
|
+
```
|
|
20
|
+
|
|
21
|
+
## Linting and formatting
|
|
22
|
+
|
|
23
|
+
To scan the project for linting and formatting errors, run
|
|
24
|
+
|
|
25
|
+
```bash
|
|
26
|
+
npm run lint
|
|
27
|
+
```
|
|
28
|
+
|
|
29
|
+
To automatically fix linting and formatting errors, run
|
|
30
|
+
|
|
31
|
+
```bash
|
|
32
|
+
npm run format
|
|
33
|
+
```
|
|
34
|
+
|
|
35
|
+
## Testing with Web Test Runner
|
|
36
|
+
|
|
37
|
+
To execute a single test run:
|
|
38
|
+
|
|
39
|
+
```bash
|
|
40
|
+
npm run test
|
|
41
|
+
```
|
|
42
|
+
|
|
43
|
+
To run the tests in interactive watch mode run:
|
|
44
|
+
|
|
45
|
+
```bash
|
|
46
|
+
npm run test:watch
|
|
47
|
+
```
|
|
48
|
+
|
|
49
|
+
## Demoing with Storybook
|
|
50
|
+
|
|
51
|
+
To run a local instance of Storybook for your component, run
|
|
52
|
+
|
|
53
|
+
```bash
|
|
54
|
+
npm run storybook
|
|
55
|
+
```
|
|
56
|
+
|
|
57
|
+
To build a production version of Storybook, run
|
|
58
|
+
|
|
59
|
+
```bash
|
|
60
|
+
npm run storybook:build
|
|
61
|
+
```
|
|
62
|
+
|
|
63
|
+
## Tooling configs
|
|
64
|
+
|
|
65
|
+
For most of the tools, the configuration is in the `package.json` to reduce the amount of files in your project.
|
|
66
|
+
|
|
67
|
+
If you customize the configuration a lot, you can consider moving them to individual files.
|
|
68
|
+
|
|
69
|
+
## Local Demo with `web-dev-server`
|
|
70
|
+
|
|
71
|
+
```bash
|
|
72
|
+
npm start
|
|
73
|
+
```
|
|
74
|
+
|
|
75
|
+
To run a local development server that serves the basic demo located in `demo/index.html`
|
package/demo/index.html
ADDED
|
@@ -0,0 +1,41 @@
|
|
|
1
|
+
<!doctype html>
|
|
2
|
+
<html lang="en-GB">
|
|
3
|
+
<head>
|
|
4
|
+
<meta charset="utf-8">
|
|
5
|
+
<style>
|
|
6
|
+
body {
|
|
7
|
+
background: #fafafa;
|
|
8
|
+
}
|
|
9
|
+
</style>
|
|
10
|
+
</head>
|
|
11
|
+
<body>
|
|
12
|
+
<div id="demo"></div>
|
|
13
|
+
|
|
14
|
+
<script type="module">
|
|
15
|
+
import { html, render } from 'lit';
|
|
16
|
+
import '../dist/src/ix-radio.js';
|
|
17
|
+
|
|
18
|
+
const handleSubmit = (e) => {
|
|
19
|
+
e.preventDefault();
|
|
20
|
+
const form = e.target;
|
|
21
|
+
const formData = new FormData(form);
|
|
22
|
+
formData.forEach((value, key) => console.log(`${key}: ${value}`));
|
|
23
|
+
}
|
|
24
|
+
|
|
25
|
+
render(
|
|
26
|
+
html`
|
|
27
|
+
<form @submit=${handleSubmit}>
|
|
28
|
+
<fieldset id="radiogroup">
|
|
29
|
+
<ix-radio label="Red" name="aName" value="red"></ix-radio><br/><br/>
|
|
30
|
+
<ix-radio label="Green" name="aName" value="green"></ix-radio><br/><br/>
|
|
31
|
+
<ix-radio label="Blue" name="aName" value="blue"></ix-radio><br/><br/>
|
|
32
|
+
<ix-radio label="Black" name="aName" value="black"></ix-radio>
|
|
33
|
+
</fieldset>
|
|
34
|
+
<button type="submit">Submit</button>
|
|
35
|
+
</form>
|
|
36
|
+
`,
|
|
37
|
+
document.querySelector('#demo')
|
|
38
|
+
);
|
|
39
|
+
</script>
|
|
40
|
+
</body>
|
|
41
|
+
</html>
|
package/demo/native.html
ADDED
|
@@ -0,0 +1,71 @@
|
|
|
1
|
+
<!doctype html>
|
|
2
|
+
<html lang="en-GB">
|
|
3
|
+
<head>
|
|
4
|
+
<meta charset="utf-8">
|
|
5
|
+
<style>
|
|
6
|
+
body {
|
|
7
|
+
background: #fafafa;
|
|
8
|
+
}
|
|
9
|
+
</style>
|
|
10
|
+
</head>
|
|
11
|
+
<body>
|
|
12
|
+
<div id="demo"></div>
|
|
13
|
+
|
|
14
|
+
<script type="module">
|
|
15
|
+
import { html, render } from 'lit';
|
|
16
|
+
import '@material/web/radio/radio.js';
|
|
17
|
+
|
|
18
|
+
const handleSubmit = (e) => {
|
|
19
|
+
e.preventDefault();
|
|
20
|
+
const form = e.target;
|
|
21
|
+
const formData = new FormData(form);
|
|
22
|
+
formData.forEach((value, key) => console.log(`${key}: ${value}`));
|
|
23
|
+
}
|
|
24
|
+
|
|
25
|
+
render(
|
|
26
|
+
html`
|
|
27
|
+
<form @submit=${handleSubmit}>
|
|
28
|
+
<div class="column" role="radiogroup" aria-label="Animals">
|
|
29
|
+
<div class="radio-label">
|
|
30
|
+
<md-radio
|
|
31
|
+
aria-label="Birds"
|
|
32
|
+
id="birds-radio"
|
|
33
|
+
name="with-labels"
|
|
34
|
+
touch-target="wrapper"
|
|
35
|
+
value="birds"
|
|
36
|
+
>
|
|
37
|
+
</md-radio>
|
|
38
|
+
<label for="birds-radio">Birds</label>
|
|
39
|
+
</div>
|
|
40
|
+
<div class="radio-label">
|
|
41
|
+
<md-radio
|
|
42
|
+
aria-label="Cats"
|
|
43
|
+
id="cats-radio"
|
|
44
|
+
name="with-labels"
|
|
45
|
+
touch-target="wrapper"
|
|
46
|
+
value="cats"
|
|
47
|
+
>
|
|
48
|
+
</md-radio>
|
|
49
|
+
<label for="cats-radio">Cats</label>
|
|
50
|
+
</div>
|
|
51
|
+
<div class="radio-label">
|
|
52
|
+
<md-radio
|
|
53
|
+
aria-label="Dogs"
|
|
54
|
+
id="dogs-radio"
|
|
55
|
+
name="with-labels"
|
|
56
|
+
touch-target="wrapper"
|
|
57
|
+
value="dogs"
|
|
58
|
+
?disabled=${true}
|
|
59
|
+
>
|
|
60
|
+
</md-radio>
|
|
61
|
+
<label for="dogs-radio">Dogs</label>
|
|
62
|
+
</div>
|
|
63
|
+
</div>
|
|
64
|
+
<button type="submit">Submit</button>
|
|
65
|
+
</form>
|
|
66
|
+
`,
|
|
67
|
+
document.querySelector('#demo')
|
|
68
|
+
);
|
|
69
|
+
</script>
|
|
70
|
+
</body>
|
|
71
|
+
</html>
|
|
@@ -0,0 +1,45 @@
|
|
|
1
|
+
import { LitElement } from 'lit';
|
|
2
|
+
import '@material/web/radio/radio.js';
|
|
3
|
+
declare const CHECKED: unique symbol;
|
|
4
|
+
export declare class IxRadio extends LitElement {
|
|
5
|
+
static get styles(): import("lit").CSSResult[];
|
|
6
|
+
/** @nocollapse */
|
|
7
|
+
static readonly formAssociated = true;
|
|
8
|
+
/**
|
|
9
|
+
* Whether or not the radio is selected.
|
|
10
|
+
*/
|
|
11
|
+
get checked(): boolean;
|
|
12
|
+
set checked(checked: boolean);
|
|
13
|
+
[CHECKED]: boolean;
|
|
14
|
+
disabled: boolean;
|
|
15
|
+
label: string;
|
|
16
|
+
/**
|
|
17
|
+
* The element value to use in form submission when checked.
|
|
18
|
+
*/
|
|
19
|
+
value: string;
|
|
20
|
+
ariaLabel: string;
|
|
21
|
+
target: 'wrapper' | '';
|
|
22
|
+
htmlId: string | undefined;
|
|
23
|
+
/**
|
|
24
|
+
* The HTML name to use in form submission.
|
|
25
|
+
*/
|
|
26
|
+
get name(): string;
|
|
27
|
+
set name(name: string);
|
|
28
|
+
/**
|
|
29
|
+
* The associated form element with which this element's value will submit.
|
|
30
|
+
*/
|
|
31
|
+
get form(): HTMLFormElement | null;
|
|
32
|
+
/**
|
|
33
|
+
* The labels this element is associated with.
|
|
34
|
+
*/
|
|
35
|
+
get labels(): NodeList;
|
|
36
|
+
private readonly selectionController;
|
|
37
|
+
private readonly internals;
|
|
38
|
+
private handleClick;
|
|
39
|
+
private handleKeydown;
|
|
40
|
+
constructor();
|
|
41
|
+
protected updated(): void;
|
|
42
|
+
get renderRadio(): import("lit-html").TemplateResult<1>;
|
|
43
|
+
render(): import("lit-html").TemplateResult<1>;
|
|
44
|
+
}
|
|
45
|
+
export {};
|
|
@@ -0,0 +1,147 @@
|
|
|
1
|
+
var _a;
|
|
2
|
+
import { __decorate } from "tslib";
|
|
3
|
+
import { html, LitElement, isServer } from 'lit';
|
|
4
|
+
import { ifDefined } from 'lit/directives/if-defined.js';
|
|
5
|
+
import { property } from 'lit/decorators.js';
|
|
6
|
+
import '@material/web/radio/radio.js';
|
|
7
|
+
import { isActivationClick } from '@material/web/internal/controller/events.js';
|
|
8
|
+
import { IxRadioStyles } from './ix-radio-styles.js';
|
|
9
|
+
import { SingleSelectionController } from './single-selection-controller.js';
|
|
10
|
+
import { polyfillElementInternalsAria } from '@material/web/internal/aria/aria.js';
|
|
11
|
+
const CHECKED = Symbol('checked');
|
|
12
|
+
export class IxRadio extends LitElement {
|
|
13
|
+
static get styles() {
|
|
14
|
+
return [IxRadioStyles];
|
|
15
|
+
}
|
|
16
|
+
/**
|
|
17
|
+
* Whether or not the radio is selected.
|
|
18
|
+
*/
|
|
19
|
+
get checked() {
|
|
20
|
+
return this[CHECKED];
|
|
21
|
+
}
|
|
22
|
+
set checked(checked) {
|
|
23
|
+
const wasChecked = this.checked;
|
|
24
|
+
if (wasChecked === checked) {
|
|
25
|
+
return;
|
|
26
|
+
}
|
|
27
|
+
this[CHECKED] = checked;
|
|
28
|
+
const state = String(checked);
|
|
29
|
+
this.internals.setFormValue(this.checked ? this.value : null, state);
|
|
30
|
+
this.requestUpdate('checked', wasChecked);
|
|
31
|
+
this.selectionController.handleCheckedChange();
|
|
32
|
+
}
|
|
33
|
+
/**
|
|
34
|
+
* The HTML name to use in form submission.
|
|
35
|
+
*/
|
|
36
|
+
get name() {
|
|
37
|
+
var _b;
|
|
38
|
+
return (_b = this.getAttribute('name')) !== null && _b !== void 0 ? _b : '';
|
|
39
|
+
}
|
|
40
|
+
set name(name) {
|
|
41
|
+
this.setAttribute('name', name);
|
|
42
|
+
}
|
|
43
|
+
/**
|
|
44
|
+
* The associated form element with which this element's value will submit.
|
|
45
|
+
*/
|
|
46
|
+
get form() {
|
|
47
|
+
return this.internals.form;
|
|
48
|
+
}
|
|
49
|
+
/**
|
|
50
|
+
* The labels this element is associated with.
|
|
51
|
+
*/
|
|
52
|
+
get labels() {
|
|
53
|
+
return this.internals.labels;
|
|
54
|
+
}
|
|
55
|
+
async handleClick(event) {
|
|
56
|
+
if (this.disabled) {
|
|
57
|
+
return;
|
|
58
|
+
}
|
|
59
|
+
// allow event to propagate to user code after a microtask.
|
|
60
|
+
await 0;
|
|
61
|
+
if (event.defaultPrevented) {
|
|
62
|
+
return;
|
|
63
|
+
}
|
|
64
|
+
if (isActivationClick(event)) {
|
|
65
|
+
this.focus();
|
|
66
|
+
}
|
|
67
|
+
// Per spec, clicking on a radio input always selects it.
|
|
68
|
+
this.checked = true;
|
|
69
|
+
this.dispatchEvent(new Event('change', { bubbles: true }));
|
|
70
|
+
this.dispatchEvent(new InputEvent('input', { bubbles: true, composed: true }));
|
|
71
|
+
}
|
|
72
|
+
async handleKeydown(event) {
|
|
73
|
+
// allow event to propagate to user code after a microtask.
|
|
74
|
+
await 0;
|
|
75
|
+
if (event.key !== ' ' || event.defaultPrevented) {
|
|
76
|
+
return;
|
|
77
|
+
}
|
|
78
|
+
this.click();
|
|
79
|
+
}
|
|
80
|
+
constructor() {
|
|
81
|
+
super();
|
|
82
|
+
this[_a] = false;
|
|
83
|
+
this.disabled = false;
|
|
84
|
+
this.label = '';
|
|
85
|
+
/**
|
|
86
|
+
* The element value to use in form submission when checked.
|
|
87
|
+
*/
|
|
88
|
+
this.value = 'on';
|
|
89
|
+
this.ariaLabel = '';
|
|
90
|
+
this.target = '';
|
|
91
|
+
this.selectionController = new SingleSelectionController(this);
|
|
92
|
+
this.internals = polyfillElementInternalsAria(this, this /* needed for closure */.attachInternals());
|
|
93
|
+
this.addController(this.selectionController);
|
|
94
|
+
if (!isServer) {
|
|
95
|
+
this.internals.role = 'radio';
|
|
96
|
+
this.addEventListener('click', this.handleClick.bind(this));
|
|
97
|
+
this.addEventListener('keydown', this.handleKeydown.bind(this));
|
|
98
|
+
}
|
|
99
|
+
}
|
|
100
|
+
updated() {
|
|
101
|
+
this.internals.ariaChecked = String(this.checked);
|
|
102
|
+
}
|
|
103
|
+
get renderRadio() {
|
|
104
|
+
return html `
|
|
105
|
+
<md-radio
|
|
106
|
+
aria-label=${this.ariaLabel || this.label}
|
|
107
|
+
name=${this.name}
|
|
108
|
+
value=${this.value}
|
|
109
|
+
?checked=${this.checked}
|
|
110
|
+
?disabled=${this.disabled}
|
|
111
|
+
id=${ifDefined(this.htmlId)}
|
|
112
|
+
touch-target=${this.target}
|
|
113
|
+
></md-radio>
|
|
114
|
+
`;
|
|
115
|
+
}
|
|
116
|
+
render() {
|
|
117
|
+
if (this.label)
|
|
118
|
+
return html `<label>${this.renderRadio}
|
|
119
|
+
<span> ${this.label}</span> </label>`;
|
|
120
|
+
return this.renderRadio;
|
|
121
|
+
}
|
|
122
|
+
}
|
|
123
|
+
_a = CHECKED;
|
|
124
|
+
/** @nocollapse */
|
|
125
|
+
IxRadio.formAssociated = true;
|
|
126
|
+
__decorate([
|
|
127
|
+
property({ type: Boolean })
|
|
128
|
+
], IxRadio.prototype, "checked", null);
|
|
129
|
+
__decorate([
|
|
130
|
+
property({ type: Boolean, reflect: true })
|
|
131
|
+
], IxRadio.prototype, "disabled", void 0);
|
|
132
|
+
__decorate([
|
|
133
|
+
property()
|
|
134
|
+
], IxRadio.prototype, "label", void 0);
|
|
135
|
+
__decorate([
|
|
136
|
+
property()
|
|
137
|
+
], IxRadio.prototype, "value", void 0);
|
|
138
|
+
__decorate([
|
|
139
|
+
property()
|
|
140
|
+
], IxRadio.prototype, "ariaLabel", void 0);
|
|
141
|
+
__decorate([
|
|
142
|
+
property()
|
|
143
|
+
], IxRadio.prototype, "target", void 0);
|
|
144
|
+
__decorate([
|
|
145
|
+
property()
|
|
146
|
+
], IxRadio.prototype, "htmlId", void 0);
|
|
147
|
+
//# sourceMappingURL=IxRadio.js.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"IxRadio.js","sourceRoot":"","sources":["../../src/IxRadio.ts"],"names":[],"mappings":"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","sourcesContent":["import { html, LitElement, isServer } from 'lit';\nimport {ifDefined} from 'lit/directives/if-defined.js';\nimport { property } from 'lit/decorators.js';\nimport '@material/web/radio/radio.js';\nimport {isActivationClick} from '@material/web/internal/controller/events.js';\nimport { IxRadioStyles } from './ix-radio-styles.js';\nimport {SingleSelectionController} from './single-selection-controller.js';\nimport {polyfillElementInternalsAria, setupHostAria} from '@material/web/internal/aria/aria.js';\n\nconst CHECKED = Symbol('checked');\n\nexport class IxRadio extends LitElement {\n static get styles() {\n return [IxRadioStyles];\n }\n\n /** @nocollapse */\n static readonly formAssociated = true;\n\n /**\n * Whether or not the radio is selected.\n */\n @property({type: Boolean})\n get checked() {\n return this[CHECKED];\n }\n set checked(checked: boolean) {\n const wasChecked = this.checked;\n if (wasChecked === checked) {\n return;\n }\n\n this[CHECKED] = checked;\n const state = String(checked);\n this.internals.setFormValue(this.checked ? this.value : null, state);\n this.requestUpdate('checked', wasChecked);\n this.selectionController.handleCheckedChange();\n }\n\n [CHECKED] = false;\n\n @property({type: Boolean, reflect: true}) disabled = false;\n\n @property() label: string = '';\n\n /**\n * The element value to use in form submission when checked.\n */\n @property() value = 'on';\n\n @property() ariaLabel: string = '';\n\n @property() target: 'wrapper' | '' = '';\n\n @property() htmlId: string | undefined;\n\n /**\n * The HTML name to use in form submission.\n */\n get name() {\n return this.getAttribute('name') ?? '';\n }\n set name(name: string) {\n this.setAttribute('name', name);\n }\n\n /**\n * The associated form element with which this element's value will submit.\n */\n get form() {\n return this.internals.form;\n }\n\n /**\n * The labels this element is associated with.\n */\n get labels() {\n return this.internals.labels;\n }\n\n private readonly selectionController = new SingleSelectionController(this);\n\n private readonly internals = polyfillElementInternalsAria(\n this, (this as HTMLElement /* needed for closure */).attachInternals());\n\n private async handleClick(event: Event) {\n if (this.disabled) {\n return;\n }\n\n // allow event to propagate to user code after a microtask.\n await 0;\n if (event.defaultPrevented) {\n return;\n }\n\n if (isActivationClick(event)) {\n this.focus();\n }\n\n // Per spec, clicking on a radio input always selects it.\n this.checked = true;\n this.dispatchEvent(new Event('change', {bubbles: true}));\n this.dispatchEvent(\n new InputEvent('input', {bubbles: true, composed: true}));\n }\n\n private async handleKeydown(event: KeyboardEvent) {\n // allow event to propagate to user code after a microtask.\n await 0;\n if (event.key !== ' ' || event.defaultPrevented) {\n return;\n }\n\n this.click();\n }\n\n constructor() {\n super();\n this.addController(this.selectionController);\n if (!isServer) {\n this.internals.role = 'radio';\n this.addEventListener('click', this.handleClick.bind(this));\n this.addEventListener('keydown', this.handleKeydown.bind(this));\n }\n }\n\n protected override updated() {\n this.internals.ariaChecked = String(this.checked);\n }\n\n get renderRadio() {\n return html`\n <md-radio\n aria-label=${this.ariaLabel || this.label }\n name=${this.name}\n value=${this.value}\n ?checked=${this.checked}\n ?disabled=${this.disabled}\n id=${ifDefined(this.htmlId)}\n touch-target=${this.target}\n ></md-radio>\n `;\n }\n\n render() {\n if (this.label)\n return html`<label>${this.renderRadio}\n <span> ${this.label}</span> </label>`;\n\n return this.renderRadio;\n }\n}\n"]}
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
export { IxRadio } from './IxRadio.js';
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"index.js","sourceRoot":"","sources":["../../src/index.ts"],"names":[],"mappings":"AAAA,OAAO,EAAE,OAAO,EAAE,MAAM,cAAc,CAAC","sourcesContent":["export { IxRadio } from './IxRadio.js';\n"]}
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
export declare const IxRadioStyles: import("lit").CSSResult;
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"ix-radio-styles.js","sourceRoot":"","sources":["../../src/ix-radio-styles.ts"],"names":[],"mappings":"AAAA,OAAO,EAAE,GAAG,EAAE,MAAM,KAAK,CAAC;AAE1B,MAAM,CAAC,MAAM,aAAa,GAAG,GAAG,CAAA,EAAE,CAAC","sourcesContent":["import { css } from 'lit';\n\nexport const IxRadioStyles = css``;\n"]}
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
export {};
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"ix-radio.js","sourceRoot":"","sources":["../../src/ix-radio.ts"],"names":[],"mappings":"AAAA,OAAO,EAAE,OAAO,EAAE,MAAM,cAAc,CAAC;AAEvC,MAAM,CAAC,cAAc,CAAC,MAAM,CAAC,UAAU,EAAE,OAAO,CAAC,CAAC","sourcesContent":["import { IxRadio } from './IxRadio.js';\n\nwindow.customElements.define('ix-radio', IxRadio);\n"]}
|
|
@@ -0,0 +1,14 @@
|
|
|
1
|
+
import React from 'react';
|
|
2
|
+
import { createComponent } from '@lit-labs/react';
|
|
3
|
+
import { IxRadio as IxRadioLit } from '../IxRadio.js';
|
|
4
|
+
window.customElements.define('ix-button', IxRadioLit);
|
|
5
|
+
export const IxButton = createComponent({
|
|
6
|
+
tagName: 'ix-radio',
|
|
7
|
+
elementClass: IxRadioLit,
|
|
8
|
+
react: React,
|
|
9
|
+
events: {
|
|
10
|
+
onclick: 'onClick',
|
|
11
|
+
onkeydown: 'keydown'
|
|
12
|
+
},
|
|
13
|
+
});
|
|
14
|
+
//# sourceMappingURL=IxRadio.js.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"IxRadio.js","sourceRoot":"","sources":["../../../src/react/IxRadio.ts"],"names":[],"mappings":"AAAA,OAAO,KAAK,MAAM,OAAO,CAAC;AAC1B,OAAO,EAAE,eAAe,EAAE,MAAM,iBAAiB,CAAC;AAClD,OAAO,EAAE,OAAO,IAAI,UAAU,EAAE,MAAM,eAAe,CAAC;AAEtD,MAAM,CAAC,cAAc,CAAC,MAAM,CAAC,WAAW,EAAE,UAAU,CAAC,CAAC;AAEtD,MAAM,CAAC,MAAM,QAAQ,GAAG,eAAe,CAAC;IACtC,OAAO,EAAE,UAAU;IACnB,YAAY,EAAE,UAAU;IACxB,KAAK,EAAE,KAAK;IACZ,MAAM,EAAE;QACN,OAAO,EAAE,SAAS;QAClB,SAAS,EAAE,SAAS;KACrB;CACF,CAAC,CAAC","sourcesContent":["import React from 'react';\nimport { createComponent } from '@lit-labs/react';\nimport { IxRadio as IxRadioLit } from '../IxRadio.js';\n\nwindow.customElements.define('ix-button', IxRadioLit);\n\nexport const IxButton = createComponent({\n tagName: 'ix-radio',\n elementClass: IxRadioLit,\n react: React,\n events: {\n onclick: 'onClick',\n onkeydown: 'keydown'\n },\n});\n"]}
|
|
@@ -0,0 +1,80 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* @license
|
|
3
|
+
* Copyright 2022 Google LLC
|
|
4
|
+
* SPDX-License-Identifier: Apache-2.0
|
|
5
|
+
*/
|
|
6
|
+
import { ReactiveController } from 'lit';
|
|
7
|
+
/**
|
|
8
|
+
* An element that supports single-selection with `SingleSelectionController`.
|
|
9
|
+
*/
|
|
10
|
+
export interface SingleSelectionElement extends HTMLElement {
|
|
11
|
+
/**
|
|
12
|
+
* Whether or not the element is selected.
|
|
13
|
+
*/
|
|
14
|
+
checked: boolean;
|
|
15
|
+
}
|
|
16
|
+
/**
|
|
17
|
+
* A `ReactiveController` that provides root node-scoped single selection for
|
|
18
|
+
* elements, similar to native `<input type="radio">` selection.
|
|
19
|
+
*
|
|
20
|
+
* To use, elements should add the controller and call
|
|
21
|
+
* `selectionController.handleCheckedChange()` in a getter/setter. This must
|
|
22
|
+
* be synchronous to match native behavior.
|
|
23
|
+
*
|
|
24
|
+
* @example
|
|
25
|
+
* const CHECKED = Symbol('checked');
|
|
26
|
+
*
|
|
27
|
+
* class MyToggle extends LitElement {
|
|
28
|
+
* get checked() { return this[CHECKED]; }
|
|
29
|
+
* set checked(checked: boolean) {
|
|
30
|
+
* const oldValue = this.checked;
|
|
31
|
+
* if (oldValue === checked) {
|
|
32
|
+
* return;
|
|
33
|
+
* }
|
|
34
|
+
*
|
|
35
|
+
* this[CHECKED] = checked;
|
|
36
|
+
* this.selectionController.handleCheckedChange();
|
|
37
|
+
* this.requestUpdate('checked', oldValue);
|
|
38
|
+
* }
|
|
39
|
+
*
|
|
40
|
+
* [CHECKED] = false;
|
|
41
|
+
*
|
|
42
|
+
* private selectionController = new SingleSelectionController(this);
|
|
43
|
+
*
|
|
44
|
+
* constructor() {
|
|
45
|
+
* super();
|
|
46
|
+
* this.addController(this.selectionController);
|
|
47
|
+
* }
|
|
48
|
+
* }
|
|
49
|
+
*/
|
|
50
|
+
export declare class SingleSelectionController implements ReactiveController {
|
|
51
|
+
private readonly host;
|
|
52
|
+
private focused;
|
|
53
|
+
private root;
|
|
54
|
+
constructor(host: SingleSelectionElement);
|
|
55
|
+
hostConnected(): void;
|
|
56
|
+
hostDisconnected(): void;
|
|
57
|
+
/**
|
|
58
|
+
* Should be called whenever the host's `checked` property changes
|
|
59
|
+
* synchronously.
|
|
60
|
+
*/
|
|
61
|
+
handleCheckedChange(): void;
|
|
62
|
+
private readonly handleFocusIn;
|
|
63
|
+
private readonly handleFocusOut;
|
|
64
|
+
private uncheckSiblings;
|
|
65
|
+
/**
|
|
66
|
+
* Updates the `tabindex` of the host and its siblings.
|
|
67
|
+
*/
|
|
68
|
+
private updateTabIndices;
|
|
69
|
+
/**
|
|
70
|
+
* Retrieves all siblings in the host element's root with the same `name`
|
|
71
|
+
* attribute.
|
|
72
|
+
*/
|
|
73
|
+
private getNamedSiblings;
|
|
74
|
+
/**
|
|
75
|
+
* Handles arrow key events from the host. Using the arrow keys will
|
|
76
|
+
* select and check the next or previous sibling with the host's
|
|
77
|
+
* `name` attribute.
|
|
78
|
+
*/
|
|
79
|
+
private readonly handleKeyDown;
|
|
80
|
+
}
|