Skip to content

Commit

Permalink
add: select
Browse files Browse the repository at this point in the history
  • Loading branch information
XboxYan committed May 5, 2023
1 parent 474d7fc commit f6812e3
Show file tree
Hide file tree
Showing 16 changed files with 760 additions and 102 deletions.
6 changes: 3 additions & 3 deletions components/button/index.css
Original file line number Diff line number Diff line change
Expand Up @@ -7,9 +7,9 @@

@supports not (color: color-mix(in srgb, red, pink)) {
:host {
--primary-color-opacity-100: rgba(255, 119, 117, 0.1);
--primary-color-opacity-200: rgba(255, 119, 117, 0.2);
--primary-color-opacity-600: rgba(255, 119, 117, 0.6);
--primary-color-opacity-100: rgba(65, 105, 225, 0.1);
--primary-color-opacity-200: rgba(65, 105, 225, 0.2);
--primary-color-opacity-600: rgba(65, 105, 225, 0.6);
}
}

Expand Down
4 changes: 2 additions & 2 deletions components/button/index.js
Original file line number Diff line number Diff line change
Expand Up @@ -43,8 +43,8 @@ export default class Button extends Base {
this.#btnEl = shadowRoot.getElementById("button");
}

focus() {
this.#btnEl.focus();
focus(options) {
this.#btnEl.focus(options);
}

get disabled() {
Expand Down
4 changes: 2 additions & 2 deletions components/checkbox/index.js
Original file line number Diff line number Diff line change
Expand Up @@ -21,8 +21,8 @@ export default class Checkbox extends Base {
this.#checkbox = shadowRoot.getElementById("checkbox");
}

focus() {
this.#checkbox.focus();
focus(options) {
this.#checkbox.focus(options);
}

get disabled() {
Expand Down
12 changes: 12 additions & 0 deletions components/optgroup/index.css
Original file line number Diff line number Diff line change
@@ -0,0 +1,12 @@
:host{
width: min-content;
}
label{
display: block;
padding: 2px 5px;
font-size: 12px;
color: var(--text-color-secondary, rgba(0, 0, 0, .45));
}
::slotted(xy-option){
text-indent: 1em;
}
58 changes: 58 additions & 0 deletions components/optgroup/index.js
Original file line number Diff line number Diff line change
@@ -0,0 +1,58 @@
import Base from "../xy-base.js";
import style from "./index.css?inline" assert { type: "css" };

export default class OptGroup extends Base {

#label;

static get observedAttributes() {
return ["disabled", "label"];
}
constructor() {
super();
const shadowRoot = this.attachShadow({ mode: "open" });
this.adoptedStyle(style);
shadowRoot.innerHTML = `
<label id="label"></label>
<slot></slot>
`;
this.#label = shadowRoot.getElementById("label");
}

get label() {
return this.getAttribute("label") || "group";
}

get disabled() {
return this.getAttribute("disabled") !== null;
}

set disabled(value) {
this.toggleAttribute("disabled", value)
}

set label(value) {
return this.setAttribute("label", value);
}

connectedCallback() {

}

async attributeChangedCallback(name, oldValue, newValue) {
await this.renderSlot();
if (name === "disabled") {
const options = [...this.querySelectorAll(`xy-option`)];
options.forEach((el) => {
el.toggleAttribute("disabled", newValue!==null)
});
}
if (name === "label") {
this.#label.textContent = newValue
}
}
}

if (!customElements.get("xy-optgroup")) {
customElements.define("xy-optgroup", OptGroup);
}
17 changes: 17 additions & 0 deletions components/option/index.css
Original file line number Diff line number Diff line change
@@ -0,0 +1,17 @@
xy-button::part(button){
justify-content: flex-start;
padding: 4px 12px;
}
:host([selected]) xy-button::part(button){
background: var(--primary-color-opacity-100);
color: var(--primary-color);
}
:host([disabled]) xy-button::part(button){
background-color: transparent;
}
xy-button::part(button):hover,
xy-button::part(button):focus{
color: inherit;
background-color: var(--primary-bg-secondary);
outline: 0;
}
153 changes: 153 additions & 0 deletions components/option/index.js
Original file line number Diff line number Diff line change
@@ -0,0 +1,153 @@
import Base from "../xy-base.js";
import style from "./index.css?inline" assert { type: "css" };
import "../button/index.js";

export default class Option extends Base {

#button;
#mounted;

static get observedAttributes() {
return ["disabled", "selected"];
}
constructor() {
super();
const shadowRoot = this.attachShadow({ mode: "open" });
this.adoptedStyle(style);
shadowRoot.innerHTML = `
<xy-button id="button" part="option" type="flat" block><slot></slot></xy-button>
`;
this.#button = shadowRoot.getElementById("button");
}

focus() {
this.#button.focus();
}

get value() {
return this.getAttribute("value") || this.textContent;
}

get label() {
return this.textContent;
}

get disabled() {
return this.getAttribute("disabled") !== null;
}

get selected() {
return this.getAttribute("selected") !== null;
}

set selected(value) {
this.toggleAttribute("selected", value)
}

set disabled(value) {
this.toggleAttribute("disabled", value)
}

set value(value) {
return this.setAttribute("value", value);
}

// 按方向键时自动选中
#focusSelect(dir) {
const options = [...this.options];
const index = options.findIndex((el) => el === document.activeElement);
let nextIndex = index + dir;
if (nextIndex < 0) {
nextIndex = options.length - 1;
}
if (nextIndex > options.length - 1) {
nextIndex = 0;
}
const next = options[nextIndex];
next.focus();
}

// 按 tab 键只聚焦一组radio中的一个,将其他radio设置为不可聚焦,inert = true
#tabChange() {
const options = [...this.options];
options.filter((el) => el !== this).forEach((el) => (el.inert = true));
}

// 按 tab 聚焦到选中的 radio
#tabFocus() {
if (!document.activeElement.selected) {
const options = [...this.options];
const current = options.find((el) => el.selected) || options[0];
current.focus();
}
}

// 按 tab 离开时还原 inert = false
#tabBlur() {
const options = [...this.options];
options.forEach((el) => (el.inert = false));
}

connectedCallback() {
if (this.#mounted) return
this.#mounted = true
if (this.parentNode.tagName === "XY-OPTGROUP") {
this.options = this.parentNode.parentNode.querySelectorAll('xy-option:not([disabled])');
} else {
this.options = this.parentNode.querySelectorAll('xy-option:not([disabled])');
}
this.addEventListener("click", () => {
this.focus()
})
this.#button.addEventListener("keydown", (ev) => {
if (!this.options.length) return;
switch (ev.key) {
case "ArrowDown":
ev.preventDefault();
this.#focusSelect(1);
break;
case "ArrowUp":
ev.preventDefault();
this.#focusSelect(-1);
break;
case "Tab":
// this.#tabChange();
break;
default:
break;
}
});
this.#button.addEventListener("focus", () => {
if (!this.options.length) return;
// this.#tabFocus();
});
this.#button.addEventListener("blur", () => {
if (!this.options.length) return;
// this.#tabBlur();
});
}

disconnectedCallback() {

}

attributeChangedCallback(name, oldValue, newValue) {
if (name === "selected" && newValue!==null) {
if (this.options?.length) {
const prev = [...this.options].find(
(el) => el.selected && el !== this
);
if (prev) {
prev.selected = false;
}
}
}
if (name === "disabled") {
this.#button.toggleAttribute("disabled", newValue!==null)
}
}
}

if (!customElements.get("xy-option")) {
customElements.define("xy-option", Option);
}
16 changes: 11 additions & 5 deletions components/pop/index.js
Original file line number Diff line number Diff line change
Expand Up @@ -12,7 +12,7 @@ export default class Pop extends Base {
this.attachShadow({ mode: "open" });
this.adoptedStyle(style);
this.shadowRoot.innerHTML = `
<div id="pop" class="pop" popover="manual">
<div id="pop" class="pop" popover="manual" part="pop">
<slot></slot>
</div>
`
Expand Down Expand Up @@ -107,11 +107,12 @@ export default class Pop extends Base {
#setPosition() {
if (this.trigger?.includes("contextmenu")) return;
if (!this.node) return
const { left, top, right, bottom } = this.node.getBoundingClientRect();
const { left, top, right, bottom, width } = this.node.getBoundingClientRect();
this.style.setProperty("--left", parseInt(left + window.pageXOffset));
this.style.setProperty("--top", parseInt(top + window.pageYOffset));
this.style.setProperty("--right", parseInt(right + window.pageXOffset));
this.style.setProperty("--bottom", parseInt(bottom + window.pageYOffset));
this.style.setProperty("--width", parseInt(width));
if (this.auto.length) {
// 自动识别位置
const w = window.innerWidth;
Expand Down Expand Up @@ -259,9 +260,10 @@ export default class Pop extends Base {
// 注册 document click
if (this._documentClickEvent.length) return
const click = (ev) => {
if (!this.contains(ev.target) && !target.contains(ev.target)) {
this.open = false;
}
const { left, top, right, bottom } = this.#pop.getBoundingClientRect()
if (ev.x > right || ev.y > bottom || ev.x < left || ev.y < top) {
this.open = false;
}
};
this._documentClickEvent.push(click)
document.addEventListener("click", click);
Expand All @@ -275,6 +277,10 @@ export default class Pop extends Base {
}
}

if (!customElements.get("xy-pop")) {
customElements.define("xy-pop", Pop);
}

/*
new Pop('el, {
tips : 'xxx',
Expand Down
16 changes: 11 additions & 5 deletions components/popover/index.js
Original file line number Diff line number Diff line change
Expand Up @@ -3,6 +3,7 @@ import Pop from "../pop/index.js";

export default class PopOver extends Pop {
#mounted;
#pop;

static get observedAttributes() {
return ["open"];
Expand All @@ -11,6 +12,7 @@ export default class PopOver extends Pop {
constructor() {
super();
this.adoptedStyle(style);
this.#pop = this.shadowRoot.getElementById('pop')
// this.shadowRoot.innerHTML = `
// <slot></slot>
// `;
Expand Down Expand Up @@ -40,13 +42,14 @@ export default class PopOver extends Pop {
document.body.append(this);
this.clientWidth;
}
this.shadowRoot.getElementById('pop').style.left = ev.pageX + 'px'
this.shadowRoot.getElementById('pop').style.top = ev.pageY + 'px'
this.#pop.style.left = ev.pageX + 'px'
this.#pop.style.top = ev.pageY + 'px'
this.open = true
if (this._documentClickEvent.length) return;
const click = (ev) => {
if (!this.contains(ev.target)) {
this.open = false
const { left, top, right, bottom } = this.#pop.getBoundingClientRect()
if (ev.x > right || ev.y > bottom || ev.x < left || ev.y < top) {
this.open = false;
}
};
this._documentClickEvent.push(click)
Expand All @@ -56,7 +59,10 @@ export default class PopOver extends Pop {
}

render(){
if (this.#mounted) return
if (this.#mounted) {
this.dispatchEvent(new Event('adopt'))
return
}
this.#mounted = true
if (!this.targetList) {
this.targetList = this.#targetAll
Expand Down
4 changes: 2 additions & 2 deletions components/radio/index.js
Original file line number Diff line number Diff line change
Expand Up @@ -7,8 +7,8 @@ export default class Radio extends Base {
return ["disabled", "checked", "required"];
}

focus() {
this.#radio.focus();
focus(options) {
this.#radio.focus(options);
}

constructor() {
Expand Down
Loading

0 comments on commit f6812e3

Please sign in to comment.