-
Notifications
You must be signed in to change notification settings - Fork 0
Commit
This commit does not belong to any branch on this repository, and may belong to a fork outside of the repository.
- Loading branch information
Showing
5 changed files
with
502 additions
and
0 deletions.
There are no files selected for viewing
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,27 @@ | ||
.base { | ||
position: relative; | ||
} | ||
|
||
.dialog { | ||
position: absolute; | ||
z-index: 1; | ||
min-width: 560px; | ||
margin-block-start: 8px; | ||
padding: 24px; | ||
background: var(--color-semantic-surface-regular-1); | ||
border: 1px solid var(--color-semantic-border-semi-weak); | ||
border-radius: 5px; | ||
box-shadow: 0 3px 12px 0 var(--color-semantic-elevation-regular); | ||
font-size: 12px; | ||
line-height: 1.6; | ||
} | ||
|
||
.dialog.position__left { | ||
left: 0; | ||
right: auto; | ||
} | ||
|
||
.dialog.position__right { | ||
left: auto; | ||
right: 0; | ||
} |
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,162 @@ | ||
// @ts-ignore | ||
import resetStyle from "@acab/reset.css?inline" assert { type: "css" }; | ||
// @ts-ignore | ||
import foundationStyle from "../foundation.css?inline" assert { type: "css" }; | ||
// @ts-ignore | ||
import dropdownDialogStyle from "./dropdown-dialog.css?inline" assert { type: "css" }; | ||
import "../button/sp-button"; | ||
|
||
type Position = "left" | "right"; | ||
|
||
const positions: Position[] = ["left", "right"]; | ||
|
||
function isValidPosition(value: string): value is Position { | ||
return positions.some((position) => position === value); | ||
} | ||
|
||
const styles = new CSSStyleSheet(); | ||
styles.replaceSync(`${resetStyle} ${foundationStyle} ${dropdownDialogStyle}`); | ||
|
||
export class SpDropdownDialog extends HTMLElement { | ||
#baseElement = document.createElement("div"); | ||
#buttonElement = document.createElement("sp-button"); | ||
#dialogElement = document.createElement("div"); | ||
#dialogSlotElement = document.createElement("slot"); | ||
|
||
#open: boolean = false; | ||
#disabled: boolean = false; | ||
#position: Position = "left"; | ||
|
||
set label(value: string) { | ||
this.#buttonElement.text = value; | ||
} | ||
|
||
get open() { | ||
return this.#open; | ||
} | ||
set open(value: boolean) { | ||
this.#open = value; | ||
|
||
if (value) { | ||
this.#buttonElement.setAttribute("selected", ""); | ||
} else { | ||
this.#buttonElement.removeAttribute("selected"); | ||
} | ||
|
||
this.#updateDialogDisplay(); | ||
} | ||
|
||
get disabled() { | ||
return this.#disabled; | ||
} | ||
set disabled(value: boolean) { | ||
this.#disabled = value; | ||
this.#buttonElement.disabled = value; | ||
this.#updateDialogDisplay(); | ||
} | ||
|
||
get position() { | ||
return this.#position; | ||
} | ||
set position(value: Position) { | ||
if (value === "left") { | ||
this.#dialogElement.classList.add("position__left"); | ||
this.#dialogElement.classList.remove("position__right"); | ||
} else { | ||
this.#dialogElement.classList.add("position__right"); | ||
this.#dialogElement.classList.remove("position__left"); | ||
} | ||
|
||
this.#position = value; | ||
} | ||
|
||
static get observedAttributes() { | ||
return ["label", "open", "disabled", "position"]; | ||
} | ||
|
||
constructor() { | ||
super(); | ||
|
||
const shadowRoot = this.attachShadow({ mode: "open" }); | ||
shadowRoot.adoptedStyleSheets = [...shadowRoot.adoptedStyleSheets, styles]; | ||
|
||
this.open = false; | ||
this.disabled = false; | ||
this.position = "left"; | ||
} | ||
|
||
connectedCallback() { | ||
this.#buttonElement.setAttribute("part", "button"); | ||
this.#buttonElement.addEventListener( | ||
"click", | ||
this.#handleClickButton.bind(this), | ||
); | ||
|
||
this.#baseElement.appendChild(this.#buttonElement); | ||
|
||
this.#dialogElement.classList.add("dialog"); | ||
this.#dialogElement.role = "dialog"; | ||
this.#dialogElement.appendChild(this.#dialogSlotElement); | ||
|
||
window.addEventListener("click", this.#handleClickOutside.bind(this)); | ||
|
||
this.#baseElement.appendChild(this.#dialogElement); | ||
this.#baseElement.classList.add("base"); | ||
|
||
this.shadowRoot?.appendChild(this.#baseElement); | ||
} | ||
|
||
disconnectedCallback() { | ||
window.removeEventListener("click", this.#handleClickOutside.bind(this)); | ||
} | ||
|
||
attributeChangedCallback(name: string, oldValue: string, newValue: string) { | ||
if (oldValue === newValue) return; | ||
switch (name) { | ||
case "label": | ||
this.label = newValue; | ||
break; | ||
case "open": | ||
this.open = newValue === "true" || newValue === ""; | ||
break; | ||
case "disabled": | ||
this.disabled = newValue === "true" || newValue === ""; | ||
break; | ||
case "position": | ||
if (isValidPosition(newValue)) { | ||
this.position = newValue; | ||
} else { | ||
console.warn(`${newValue}は無効なposition属性です。`); | ||
this.position = "left"; | ||
} | ||
} | ||
} | ||
|
||
#handleClickButton(event: MouseEvent) { | ||
event.stopPropagation(); | ||
|
||
this.open = !this.open; | ||
} | ||
|
||
#handleClickOutside(event: MouseEvent) { | ||
event.stopPropagation(); | ||
|
||
if (!this.contains(event.target as Node)) { | ||
this.open = false; | ||
} | ||
} | ||
|
||
#updateDialogDisplay() { | ||
this.#dialogElement.style.display = | ||
this.open && !this.disabled ? "block" : "none"; | ||
} | ||
} | ||
|
||
declare global { | ||
interface HTMLElementTagNameMap { | ||
"sp-dropdown-dialog": SpDropdownDialog; | ||
} | ||
} | ||
|
||
customElements.get("sp-dropdown-dialog") || | ||
customElements.define("sp-dropdown-dialog", SpDropdownDialog); |
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,67 @@ | ||
import "@sp-design/token/lib/speeda-tokens.css"; | ||
import type { Meta, StoryObj } from "@storybook/web-components"; | ||
import { html } from "lit"; | ||
import "../../src/components/dropdownDialog/sp-dropdown-dialog"; | ||
|
||
const meta: Meta = { | ||
component: "sp-dropdown-dialog", | ||
argTypes: {}, | ||
args: {}, | ||
}; | ||
export default meta; | ||
|
||
type Story = StoryObj; | ||
|
||
export const Basic: Story = { | ||
render: () => html` | ||
<sp-dropdown-dialog label="ダイアログを表示"> | ||
<h1>ダイアログのタイトル</h1> | ||
ダイアログの内容 | ||
</sp-dropdown-dialog> | ||
`, | ||
}; | ||
|
||
export const LongText: Story = { | ||
render: () => html` | ||
<sp-dropdown-dialog label="検索式を表示"> | ||
<h1>検索式</h1> | ||
<div>S001 FI:G08G1/16?</div> | ||
<div>S002 FI:B60W30?+B60W40?+B60W50?</div> | ||
<div>S003 FI:B60?+G01C21/?+G08G1/?+G05D1/?</div> | ||
<div> | ||
S004 | ||
全文:?先進運転支援?+?高度運転支援?+?advanced?*?driver-assistance?*?systems? | ||
</div> | ||
<div> | ||
S005 | ||
名称+要約+請求項:?自動運転?+?自動走行?+?自律運転?+?自律走行?+?オートクルーズ?+?衝突被害軽減?+?車間距離制御?+?アダプティブクルーズコントロール?+?アダプティブフロントライティング?+?車線維持支援?+?車線逸脱防止?+?車線逸脱警告?+?死角検出?+?死角検知?+?死角モニタ?+?クロストラフィックアラート?+?駐車支援?+?パーキングアシスト?+?トラフィックジャムアシスト?+?渋滞運転支援?+?ナイトビジョン?+?暗視? | ||
</div> | ||
<div>S006 名称+要約+請求項:[?自動?*?ブレーキ?,?制動?]W3</div> | ||
<div> | ||
S007 名称+要約+請求項:[?歩行者?,?標識?,?居眠?*?検知?,?検出?,?認識?]W3 | ||
</div> | ||
<div>S008 名称+要約+請求項:[?前方?*?衝突?]W3</div> | ||
<div> | ||
S009 名称+要約+請求項:[?運転者?,?運転手?,?ドライバ?*?監視?,?モニタ?]W3 | ||
</div> | ||
<div>S010 論理式:S001+S002+S003*(S004+S005+S006+S007+S008+S009)</div> | ||
</sp-dropdown-dialog> | ||
`, | ||
}; | ||
|
||
export const RightPosition: Story = { | ||
render: () => html` | ||
<div style="display: flex; justify-content: end"> | ||
<sp-dropdown-dialog label="ダイアログを表示" open position="right"> | ||
<h1>ダイアログのタイトル</h1> | ||
ダイアログの内容 | ||
</sp-dropdown-dialog> | ||
</div> | ||
`, | ||
}; | ||
|
||
export const Disabled: Story = { | ||
render: () => html` | ||
<sp-dropdown-dialog label="ダイアログを表示" disabled></sp-dropdown-dialog> | ||
`, | ||
}; |
Oops, something went wrong.