Skip to content

Commit 9f3744a

Browse files
eumarciel404favna
andauthored
feat: add string select menu (#436)
closes #185 * fix: updating types export Incluindo DiscordSelectMenuProps and DicordSelectMenuOptionProps in types * Update index.ts Add news components in createReactComponent * feat: create string select menu * Update index.ts * Update package.json If you want to change something, feel free * Update package.json If you want to change something, feel free * fix: Changing classname check I changed the way of checking because this way the checking is better and there are no risks if you add something to the classname and also because eslint suggested * refactor: cleanup, fix bugs, and some rework * chore: clean types --------- Co-authored-by: Jeroen Claassens <support@favware.tech>
1 parent 169c7af commit 9f3744a

File tree

7 files changed

+314
-0
lines changed

7 files changed

+314
-0
lines changed

packages/core/demo/index.html

+51
Original file line numberDiff line numberDiff line change
@@ -492,6 +492,57 @@ <h3 class="title">Components</h3>
492492
>Link</discord-button
493493
>
494494
</discord-action-row>
495+
<dicord-action-row>
496+
<discord-string-select-menu>
497+
<discord-string-select-menu-option
498+
label="Label"
499+
description="Description"
500+
emoji="https://raw.githubusercontent.com/skyra-project/discord-components-implementations/main/shared/public/eyes.svg"
501+
></discord-string-select-menu-option>
502+
<discord-string-select-menu-option
503+
label="Label no Emoji"
504+
description="Description no Emoji"
505+
></discord-string-select-menu-option>
506+
</discord-string-select-menu>
507+
</dicord-action-row>
508+
<dicord-action-row>
509+
<discord-string-select-menu disabled="true" placeholder="Disabled Select Menu">
510+
<discord-string-select-menu-option
511+
label="Test"
512+
description="Test"
513+
emoji="https://raw.githubusercontent.com/skyra-project/discord-components-implementations/main/shared/public/eyes.svg"
514+
></discord-string-select-menu-option>
515+
<discord-string-select-menu-option label="Teste2"> </discord-string-select-menu-option>
516+
</discord-string-select-menu>
517+
</dicord-action-row>
518+
<dicord-action-row>
519+
<discord-string-select-menu placeholder="overflow">
520+
<discord-string-select-menu-option
521+
label="Favna"
522+
description="I am a developer hailing from The Netherlands"
523+
></discord-string-select-menu-option>
524+
<discord-string-select-menu-option
525+
label="Kira"
526+
description="I am an enthusiast videogame development"
527+
></discord-string-select-menu-option>
528+
<discord-string-select-menu-option
529+
label="Marciel404"
530+
description="I am a back-end developer and front-end"
531+
></discord-string-select-menu-option>
532+
<discord-string-select-menu-option
533+
label="Skyra"
534+
description="Skyra 6.3.0 [Sapphire Edition] is a multi-purpose Discord Bot designed to run the majority of tasks in your server with great performance and uptime. I use the Sapphire Framework for the Discord.js library. "
535+
></discord-string-select-menu-option>
536+
<discord-string-select-menu-option
537+
label="Iriss"
538+
description="Iriss is a bot focused on suggestion management. This is an HTTP only bot built on top of Skyra HTTP Framework."
539+
></discord-string-select-menu-option>
540+
<discord-string-select-menu-option
541+
label="Nekokai"
542+
description="Nekokai is a bot focused in information and media from anime and manga. This is an HTTP only bot built on top of Skyra HTTP Framework."
543+
></discord-string-select-menu-option>
544+
</discord-string-select-menu>
545+
</dicord-action-row>
495546
</discord-attachments>
496547
</discord-message>
497548
</discord-messages>

packages/core/package.json

+4
Original file line numberDiff line numberDiff line change
@@ -42,6 +42,8 @@
4242
"./discord-reactions.js": "./dist/components/discord-reactions/DiscordReactions.js",
4343
"./discord-reply.js": "./dist/components/discord-reply/DiscordReply.js",
4444
"./discord-spoiler.js": "./dist/components/discord-spoiler/DiscordSpoiler.js",
45+
"./discord-string-select-menu.js": "./dist/components/discord-string-select-menu/DiscordStringSelectMenu.js",
46+
"./discord-string-select-menu-option.js": "./dist/components/discord-string-select-menu-option/DiscordStringSelectMenuOption.js",
4547
"./discord-subscript.js": "./dist/components/discord-subscript/DiscordSubscript.js",
4648
"./discord-system-message.js": "./dist/components/discord-system-message/DiscordSystemMessage.js",
4749
"./discord-tenor-video.js": "./dist/components/discord-tenor-video/DiscordTenorVideo.js",
@@ -85,6 +87,8 @@
8587
"./dist/components/discord-reactions/DiscordReactions.js",
8688
"./dist/components/discord-reply/DiscordReply.js",
8789
"./dist/components/discord-spoiler/DiscordSpoiler.js",
90+
"./dist/components/discord-string-select-menu/DiscordStringSelectMenu.js",
91+
"./dist/components/discord-string-select-menu-option/DiscordStringSelectMenuOption.js",
8892
"./dist/components/discord-subscript/DiscordSubscript.js",
8993
"./dist/components/discord-system-message/DiscordSystemMessage.js",
9094
"./dist/components/discord-tenor-video/DiscordTenorVideo.js",
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,94 @@
1+
import { css, html, LitElement } from 'lit';
2+
import { customElement, property } from 'lit/decorators.js';
3+
import { ifDefined } from 'lit/directives/if-defined.js';
4+
import { when } from 'lit/directives/when.js';
5+
import { DiscordComponentsError } from '../../util.js';
6+
7+
@customElement('discord-string-select-menu-option')
8+
export class DiscordStringSelectMenuOption extends LitElement {
9+
public static override readonly styles = css`
10+
:host {
11+
display: flex;
12+
align-items: center;
13+
max-width: 400px;
14+
padding: 8px 8px 8px 12px;
15+
gap: 10px;
16+
font-size: small;
17+
max-width: 95%;
18+
}
19+
20+
:host(:hover) {
21+
background-color: rgba(0, 0, 0, 0.1);
22+
}
23+
24+
.discord-string-select-menu-option-emoji {
25+
margin-right: 4px;
26+
object-fit: contain;
27+
width: 1.375em;
28+
height: 1.375em;
29+
vertical-align: bottom;
30+
}
31+
32+
.discord-string-select-menu-option-max-size {
33+
display: block;
34+
overflow: hidden;
35+
text-overflow: ellipsis;
36+
white-space: nowrap;
37+
max-width: 390px;
38+
}
39+
`;
40+
41+
/**
42+
* The emoji URL to use in the SelectMenu.
43+
*/
44+
@property({ reflect: true, attribute: 'emoji' })
45+
public accessor emoji: string;
46+
47+
/**
48+
* The name of the emoji used in the SelectMenu.
49+
*/
50+
@property({ reflect: true, attribute: 'emoji-name' })
51+
public accessor emojiName = 'emoji';
52+
53+
/**
54+
* The label of the option
55+
*/
56+
@property({ attribute: 'label' })
57+
public accessor label: string;
58+
59+
/**
60+
* The description of the option
61+
*/
62+
@property({ attribute: 'description' })
63+
public accessor description: string;
64+
65+
public checkLabelIsProvided() {
66+
if (!this.label) {
67+
throw new DiscordComponentsError('The label of option is required');
68+
}
69+
}
70+
71+
protected override render() {
72+
this.checkLabelIsProvided();
73+
74+
return html`
75+
${when(
76+
this.emoji,
77+
() =>
78+
html`<img src=${this.emoji} alt=${ifDefined(this.emojiName)} draggable="true" class="discord-string-select-menu-option-emoji" />`
79+
)}
80+
<div>
81+
<div>
82+
<strong class="discord-string-select-menu-option-max-size">${this.label}</strong>
83+
</div>
84+
${when(this.description, () => html`<span class="discord-string-select-menu-option-max-size">${this.description}</span>`)}
85+
</div>
86+
`;
87+
}
88+
}
89+
90+
declare global {
91+
interface HTMLElementTagNameMap {
92+
'discord-string-select-menu-option': DiscordStringSelectMenuOption;
93+
}
94+
}
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,149 @@
1+
import { css, html, LitElement } from 'lit';
2+
import { customElement, eventOptions, property } from 'lit/decorators.js';
3+
import { classMap } from 'lit/directives/class-map.js';
4+
import ExpandMore from '../svgs/ExpandMore.js';
5+
6+
@customElement('discord-string-select-menu')
7+
export class DiscordStringSelectMenu extends LitElement {
8+
public static override readonly styles = css`
9+
.discord-string-select-menu {
10+
height: 36px;
11+
min-height: 36px;
12+
display: flex;
13+
align-items: center;
14+
justify-content: space-between;
15+
box-sizing: border-box;
16+
cursor: pointer;
17+
color: color-mix(in oklab, hsl(210 calc(1 * 9.1%) 87.1% / 1) 100%, black 0%);
18+
border: 1px solid;
19+
border-radius: 4px;
20+
background-color: color-mix(in oklab, hsl(225 calc(1 * 6.3%) 12.5% / 1) 100%, black 0%);
21+
border-color: color-mix(in oklab, hsl(225 calc(1 * 6.3%) 12.5% / 1) 100%, black 0%);
22+
padding: 8px !important;
23+
width: 90%;
24+
max-width: 400px;
25+
margin-right: 16px;
26+
transition: border 0.2s ease;
27+
font-weight: 500;
28+
}
29+
30+
.discord-string-select-menu-option-slot {
31+
overflow-y: scroll;
32+
overflow-x: hidden;
33+
color: currentColor;
34+
border: none;
35+
border-top-left-radius: 0px;
36+
border-top-right-radius: 0px;
37+
border-color: color-mix(in oklab, hsl(225 calc(1 * 6.3%) 12.5% / 1) 100%, black 0%);
38+
background-color: color-mix(in oklab, hsl(220 calc(1 * 6.5%) 18% / 1) 100%, black 0%);
39+
40+
cursor: pointer;
41+
box-sizing: border-box;
42+
border-radius: 4px;
43+
gap: 10px;
44+
display: block;
45+
max-height: 282px;
46+
position: absolute;
47+
48+
width: 90%;
49+
max-width: 400px;
50+
z-index: 1002;
51+
}
52+
53+
.discord-string-select-menu-option-slot::-webkit-scrollbar {
54+
width: 5px;
55+
background-color: transparent;
56+
}
57+
58+
.discord-string-select-menu-option-slot::-webkit-scrollbar-track {
59+
background-color: none;
60+
}
61+
62+
.discord-string-select-menu-option-slot::-webkit-scrollbar-thumb {
63+
border-radius: 10px;
64+
background-color: rgba(0, 0, 0, 0.3);
65+
}
66+
67+
.discord-string-select-menu-label {
68+
width: 100%;
69+
}
70+
71+
.discord-string-select-inside-menu {
72+
padding: 8px 8px 8px 12px;
73+
display: flex;
74+
align-items: center;
75+
justify-content: space-between;
76+
}
77+
78+
.discord-string-select-menu-hidden {
79+
display: none;
80+
}
81+
82+
.discord-string-select-menu-disabled {
83+
cursor: not-allowed !important;
84+
opacity: 0.5;
85+
}
86+
87+
.discord-string-select-inside-menu:hover {
88+
border-color: black;
89+
cursor: pointer;
90+
}
91+
92+
.discord-string-select-menu-rotated {
93+
transform: rotate(-180deg);
94+
}
95+
96+
.discord-expand-more-icon {
97+
margin-left: auto;
98+
}
99+
`;
100+
101+
/**
102+
* Whether to show the `discord-string-select-menu` as disabled.
103+
*/
104+
@property({ type: Boolean, attribute: 'disabled' })
105+
public accessor disabled: boolean;
106+
107+
/**
108+
* The placeholder of the select-menu
109+
*/
110+
@property({ attribute: 'placeholder' })
111+
public accessor placeholder: string = 'Make a selection';
112+
113+
protected override render() {
114+
return html`
115+
<div class="${classMap({ 'discord-string-select-menu': true, 'discord-string-select-menu-disabled': this.disabled })}">
116+
<label class="discord-string-select-menu-label">
117+
<div class="${classMap({ 'discord-string-select-inside-menu': true, 'discord-string-select-menu-disabled': this.disabled })}">
118+
<span>${this.placeholder}</span> ${ExpandMore({ class: 'discord-expand-more-icon' })}
119+
<span class="discord-string-select-menu-hidden"><input type="checkbox" @click=${this._onClick} /></span>
120+
</div>
121+
</label>
122+
</div>
123+
<div class="discord-string-select-menu-option-slot discord-string-select-menu-hidden"><slot></slot></div>
124+
`;
125+
}
126+
127+
@eventOptions({ once: false, capture: true, passive: true })
128+
private _onClick() {
129+
const expandMoreIcon = this.shadowRoot?.querySelectorAll('svg.discord-expand-more-icon').item(0);
130+
const optionsMenu = this.shadowRoot?.querySelectorAll('div.discord-string-select-menu-option-slot').item(0);
131+
const stringSelectMenu = this.shadowRoot?.querySelectorAll('div.discord-string-select-menu').item(0);
132+
133+
if (stringSelectMenu?.className.includes('discord-string-select-menu-disabled')) return;
134+
135+
if (optionsMenu?.className.includes('discord-string-select-menu-hidden')) {
136+
optionsMenu?.setAttribute('class', 'discord-string-select-menu-option-slot');
137+
expandMoreIcon?.setAttribute('class', 'discord-expand-more-icon discord-string-select-menu-rotated');
138+
} else {
139+
optionsMenu?.setAttribute('class', 'discord-string-select-menu-option-slot discord-string-select-menu-hidden');
140+
expandMoreIcon?.setAttribute('class', 'discord-expand-more-icon');
141+
}
142+
}
143+
}
144+
145+
declare global {
146+
interface HTMLElementTagNameMap {
147+
'discord-string-select-menu': DiscordStringSelectMenu;
148+
}
149+
}
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,12 @@
1+
import { spread } from '@open-wc/lit-helpers';
2+
import { html, svg } from 'lit';
3+
4+
const svgContent = svg`
5+
<path fill="currentColor" d="M5.3 9.3a1 1 0 0 1 1.4 0l5.3 5.29 5.3-5.3a1 1 0 1 1 1.4 1.42l-6 6a1 1 0 0 1-1.4 0l-6-6a1 1 0 0 1 0-1.42Z"></path>
6+
`;
7+
8+
export default function ExpandMore(props: Record<string, unknown> = {}) {
9+
return html`<svg ${spread(props)} aria-hidden="false" width="18" height="18" viewBox="0 0 24 24" xmlns="http://www.w3.org/2000/svg">
10+
${svgContent}
11+
</svg>`;
12+
}

packages/core/src/index.ts

+2
Original file line numberDiff line numberDiff line change
@@ -33,6 +33,8 @@ export { DiscordReaction } from './components/discord-reaction/DiscordReaction.j
3333
export { DiscordReactions } from './components/discord-reactions/DiscordReactions.js';
3434
export { DiscordReply } from './components/discord-reply/DiscordReply.js';
3535
export { DiscordSpoiler } from './components/discord-spoiler/DiscordSpoiler.js';
36+
export { DiscordStringSelectMenu } from './components/discord-string-select-menu/DiscordStringSelectMenu.js';
37+
export { DiscordStringSelectMenuOption } from './components/discord-string-select-menu-option/DiscordStringSelectMenuOption.js';
3638
export { DiscordSubscript } from './components/discord-subscript/DiscordSubscript.js';
3739
export { DiscordSystemMessage } from './components/discord-system-message/DiscordSystemMessage.js';
3840
export { DiscordTenorVideo } from './components/discord-tenor-video/DiscordTenorVideo.js';

packages/react/src/index.ts

+2
Original file line numberDiff line numberDiff line change
@@ -34,6 +34,8 @@ export const DiscordReaction = createReactComponent('discord-reaction', ReactCom
3434
export const DiscordReactions = createReactComponent('discord-reactions', ReactComponents.DiscordReactions);
3535
export const DiscordReply = createReactComponent('discord-reply', ReactComponents.DiscordReply);
3636
export const DiscordSpoiler = createReactComponent('discord-spoiler', ReactComponents.DiscordSpoiler);
37+
export const DiscordStringSelectMenu = createReactComponent('discord-string-select-menu', ReactComponents.DiscordStringSelectMenu);
38+
export const DiscordStringSelectMenuOption = createReactComponent('discord-string-select-menu-option', ReactComponents.DiscordStringSelectMenuOption);
3739
export const DiscordSubscript = createReactComponent('discord-subscript', ReactComponents.DiscordSubscript);
3840
export const DiscordSystemMessage = createReactComponent('discord-system-message', ReactComponents.DiscordSystemMessage);
3941
export const DiscordTenorVideo = createReactComponent('discord-tenor-video', ReactComponents.DiscordTenorVideo);

0 commit comments

Comments
 (0)