Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

feat(select): add select/dropdown component #35

Merged
merged 9 commits into from
Oct 14, 2024
2 changes: 2 additions & 0 deletions src/primevue/index.ts
Original file line number Diff line number Diff line change
Expand Up @@ -15,6 +15,7 @@ import radioButton from "./radioButton/radioButton";
import autocomplete from "./autocomplete/autocomplete";
import textarea from "./textarea/textarea";
import toast from "./toast/toast";
import select from "./select/select";
import inputMask from "./inputMask/inputMask";

import { deDE } from "@/config/locale";
Expand All @@ -35,6 +36,7 @@ export const RisUiTheme = {
textarea,
toast,
autocomplete,
select,
inputMask,
};

Expand Down
1 change: 1 addition & 0 deletions src/primevue/inputText/inputText.ts
Original file line number Diff line number Diff line change
@@ -1,6 +1,7 @@
import { tw } from "@/lib/tags";
import { InputTextPassThroughOptions } from "primevue/inputtext";
import "./inputText.css";

// Base
export const base = tw`border-2 border-blue-800 bg-white outline-4 -outline-offset-4 outline-blue-800 placeholder:text-gray-800 read-only:cursor-not-allowed read-only:border-blue-300 read-only:bg-blue-300 hover:outline focus:outline disabled:border-blue-500 disabled:bg-white disabled:text-blue-500 disabled:outline-none aria-[invalid]:border-red-800 aria-[invalid]:bg-red-200 aria-[invalid]:outline-red-800 aria-[invalid]:disabled:outline-none`;

Expand Down
7 changes: 7 additions & 0 deletions src/primevue/select/select.css
Original file line number Diff line number Diff line change
@@ -0,0 +1,7 @@
div + small {
@apply ris-label3-regular mt-4 flex items-center gap-4 text-gray-900;
}

div[aria-invalid="true"] + small {
@apply text-red-900;
}
159 changes: 159 additions & 0 deletions src/primevue/select/select.stories.ts
Original file line number Diff line number Diff line change
@@ -0,0 +1,159 @@
import { html } from "@/lib/tags";
import { Meta, StoryObj } from "@storybook/vue3";
import PrimevueSelect from "primevue/select";
import { ref } from "vue";
import ErrorOutline from "~icons/material-symbols/error-outline";

const meta: Meta<typeof PrimevueSelect> = {
component: PrimevueSelect,

tags: ["autodocs"],

args: {
placeholder: "Dropdown",
disabled: false,
invalid: false,
},
};

export default meta;

export const Default: StoryObj<typeof meta> = {
render: (args) => ({
components: { PrimevueSelect },
setup() {
const selectedOption = ref();
const options = ref([
{ name: "Text 1", code: "AB" },
{ name: "Text 2", code: "CD" },
{ name: "Text 3", code: "EF" },
{ name: "Text 4", code: "GH" },
{ name: "Text 5", code: "IJ" },
]);
return { args, selectedOption, options };
},
template: html` <PrimevueSelect
v-bind="args"
v-model="selectedOption"
optionLabel="name"
:options="options"
/>`,
}),
};

export const WithLabel: StoryObj<typeof meta> = {
args: {
disabled: false,
},
render: (args) => ({
components: { PrimevueSelect },
setup() {
const selectedOption = ref();
const options = ref([
{ name: "Text 1", code: "AB" },
{ name: "Text 2", code: "CD" },
{ name: "Text 3", code: "EF" },
{ name: "Text 4", code: "GH" },
{ name: "Text 5", code: "IJ" },
]);
return { args, selectedOption, options };
},
template: html`<div class="flex flex-col gap-2">
<label class="ris-label2-regular" for="with-top-label">Label</label>
<PrimevueSelect
id="with-top-label"
v-bind="args"
v-model="selectedOption"
optionLabel="name"
:options="options"
/>
</div>`,
}),
};

export const WithHorizontalLabel: StoryObj<typeof meta> = {
render: (args) => ({
components: { PrimevueSelect },
setup() {
const selectedOption = ref();
const options = ref([
{ name: "Text 1", code: "AB" },
{ name: "Text 2", code: "CD" },
{ name: "Text 3", code: "EF" },
{ name: "Text 4", code: "GH" },
{ name: "Text 5", code: "IJ" },
]);
return { args, selectedOption, options };
},
template: html`<div class="flex w-1/2 items-center gap-16">
<label class="ris-label2-regular" for="with-left-label">Label</label>
<PrimevueSelect
id="with-left-label"
v-bind="args"
v-model="selectedOption"
optionLabel="name"
:options="options"
fluid
/>
</div>`,
}),
};

export const Disabled: StoryObj<typeof meta> = {
args: {
disabled: true,
},
render: (args) => ({
components: { PrimevueSelect },
setup() {
const selectedOption = ref();
const options = ref([
{ name: "Text 1", code: "AB" },
{ name: "Text 2", code: "CD" },
{ name: "Text 3", code: "EF" },
{ name: "Text 4", code: "GH" },
{ name: "Text 5", code: "IJ" },
]);
return { args, selectedOption, options };
},
template: html` <PrimevueSelect
id="with-top-label"
v-bind="args"
v-model="selectedOption"
optionLabel="name"
:options="options"
/>`,
}),
};

export const Invalid: StoryObj<typeof meta> = {
args: {
invalid: true,
},
render: (args) => ({
components: { PrimevueSelect, ErrorOutline },
setup() {
const selectedOption = ref();
const options = ref([
{ name: "Text 1", code: "AB" },
{ name: "Text 2", code: "CD" },
{ name: "Text 3", code: "EF" },
{ name: "Text 4", code: "GH" },
{ name: "Text 5", code: "IJ" },
]);
return { args, selectedOption, options };
},
template: html` <div class="flex flex-col gap-2">
<label class="ris-label2-regular" for="invalid"> Dropdown </label>
<PrimevueSelect
id="invalid"
aria-describedby="invalid-hint"
v-bind="args"
v-model="selectedOption"
optionLabel="name"
:options="options"
/>
<small id="invalid-hint"><ErrorOutline />Invalid date</small>
</div>`,
}),
};
71 changes: 71 additions & 0 deletions src/primevue/select/select.ts
Original file line number Diff line number Diff line change
@@ -0,0 +1,71 @@
import { tw } from "@/lib/tags.ts";
import { SelectPassThroughOptions } from "primevue/select";
import "./select.css";

const select: SelectPassThroughOptions = {
root: ({ props, state }) => {
// Base
const base = tw`ris-body2-regular inline-flex h-48 items-center justify-between border-2 py-4 pl-16 pr-12 outline-4 -outline-offset-4 [&+label]:ml-8`;

// States
const normal = tw`cursor-pointer border-blue-800 outline-blue-800`;

const focused = tw`outline`;

const hover = tw`hover:outline`;

const disabled = tw`cursor-not-allowed border-blue-500 text-blue-500`;

const invalid = tw`border-red-800 bg-red-200 outline-red-800`;

// Integration for primevue/fluid
const fluid = tw`w-full`;

return {
class: {
[base]: true,
[normal]: !props.disabled,
[focused]: state.focused && !props.disabled,
[hover]: !props.disabled,
[fluid]: !!props.fluid,
[disabled]: props.disabled,
[invalid]: props.invalid,
},

"aria-invalid": props.invalid ? "true" : null,
};
},

dropdown: {
class: tw`pl-12`,
},

listContainer: {
class: tw`overflow-auto shadow-md`,
},

label: {
class: tw`outline-none`,
},

overlay: {
class: tw`bg-white`,
},

option: ({ context }) => {
// Base
const base = tw`ris-body2-regular relative h-full min-h-48 w-full cursor-pointer px-24 py-16 after:absolute after:-bottom-1 after:left-8 after:right-8 after:border-b after:border-gray-300 after:content-[''] last:after:border-b-0 hover:bg-gray-100`;

// States
const focused = tw`bg-gray-100`;

return {
class: {
[base]: true,
[focused]: context.focused,
},
};
},
};

export default select;
Loading