Commit 599e574a authored by Дмитрий Малюгин's avatar Дмитрий Малюгин 🕓
Browse files

feat: add logic for Select and create 'SelectItem' component

parent 69c55394
Loading
Loading
Loading
Loading
+7 −3
Original line number Diff line number Diff line
@@ -58,9 +58,11 @@ export interface IMDItemProps {
export interface ISelectOption {
  value: string;
  label?: string;
  group?: string;
  iconLeft?: TIcons;
  iconRight?: TIcons;
  iconColor?: TThemeColor;
  iconLeftColor?: TThemeColor;
  iconRightColor?: TThemeColor;
  color?: TThemeColor;
  darknessColor?: TDarkness;
  background?: TThemeColor;
@@ -68,10 +70,12 @@ export interface ISelectOption {
}

export interface ISelectGroup {
  title: string;
  name: string;
  titleColor?: TThemeColor;
  iconLeft?: TIcons;
  iconRight?: TIcons;
  items: string[];
  iconLeftColor?: TThemeColor;
  iconRightColor?: TThemeColor;
}

export interface ISBOption {
+3 −0
Original line number Diff line number Diff line
@@ -134,8 +134,11 @@ export interface ISelectProps {
  name?: string;
  theme?: TThemeColor;
  background?: TThemeColor;
  placeholderColor?: TThemeColor;
  openIconColor?: TThemeColor;
  darknessTheme?: TDarkness;
  darknessBackground?: TDarkness;
  darknessOpenIcon?: TDarkness;
  disabled?: boolean;
}

+2 −2
Original line number Diff line number Diff line
@@ -102,7 +102,7 @@ export const Full: Story = {
  },
};

export const Down: Story = {
export const Vertical: Story = {
  args: {
    items: [
      {
@@ -125,7 +125,7 @@ export const Down: Story = {
  },
};

export const Huge: Story = {
export const Full2: Story = {
  args: {
    items: [
      {
+45 −1
Original line number Diff line number Diff line
import type { Meta, StoryObj } from '@storybook/vue3';

import Select from './Select.vue';
import { iconsSet } from '@/common/constants/icons';

const meta: Meta = {
  title: 'Components/Select',
@@ -18,9 +19,11 @@ const meta: Meta = {
    disabled: { control: 'boolean' },
    placeholder: { control: 'text' },
    name: { control: 'text' },
    openIcon: { control: 'select', options: Object.keys(iconsSet) },
    size: { control: 'select', options: ['small', 'normal', 'large', 'huge'] },
    darknessTheme: { control: 'select', options: ['100', '200', '300', '400', '500', '600', '700', '800', '900'] },
    darknessBackground: { control: 'select', options: ['100', '200', '300', '400', '500', '600', '700', '800', '900'] },
    darknessOpenIcon: { control: 'select', options: ['100', '200', '300', '400', '500', '600', '700', '800', '900'] },
    theme: {
      control: 'select',
      options: [
@@ -61,6 +64,46 @@ const meta: Meta = {
        'black',
      ],
    },
    openIconColor: {
      control: 'select',
      options: [
        'white',
        'blue',
        'sky',
        'cyan',
        'teal',
        'green',
        'yellow',
        'orange',
        'pink',
        'fuchsia',
        'purple',
        'indigo',
        'rose',
        'red',
        'black',
      ],
    },
    placeholderColor: {
      control: 'select',
      options: [
        'white',
        'blue',
        'sky',
        'cyan',
        'teal',
        'green',
        'yellow',
        'orange',
        'pink',
        'fuchsia',
        'purple',
        'indigo',
        'rose',
        'red',
        'black',
      ],
    },
  },
} satisfies Meta<typeof Select>;

@@ -95,7 +138,7 @@ export const Full: Story = {
      },
      {
        value: 'Second',
        iconColor: 'red',
        iconRightColor: 'red',
        iconRight: 'Age18',
      },
      {
@@ -112,5 +155,6 @@ export const Full: Story = {
    background: 'sky',
    darknessTheme: '700',
    darknessBackground: '200',
    openIconColor: 'sky',
  },
};
+44 −80
Original line number Diff line number Diff line
@@ -4,6 +4,7 @@ import { computed, ref } from 'vue';
import { convertThemeToColor } from '@helpers/common';
import { iconsSet } from '@/common/constants/icons';
import type { TThemeColor } from '@interfaces/common';
import SelectItem from '@stories/components/Select/SelectItem.vue';

const props = withDefaults(defineProps<ISelectProps>(), {
  size: 'normal',
@@ -11,22 +12,20 @@ const props = withDefaults(defineProps<ISelectProps>(), {
  theme: 'black',
  darknessTheme: '700',
  darknessBackground: '200',
  darknessOpenIcon: '700',
  name: 'select',
  placeholder: 'Nothing selected',
  openIcon: 'ArrowShortDown',
});
const selected = defineModel('value');
// watch(, () => {});
const isOpen = ref<boolean>(false);

const selectedOption = computed(() => props.options.find((option) => option.value === selected.value));
const textColor = computed(() => convertThemeToColor(props.theme, props.darknessTheme));
const textColor = computed(() => (props.disabled ? '#62708c' : convertThemeToColor(props.theme, props.darknessTheme)));
const backgroundColor = computed(() =>
  convertThemeToColor(
    props.background ?? (props.theme === 'white' ? 'black' : props.theme === 'black' ? 'white' : props.theme),
    (!props.background && props.theme === 'black') || (props.background === 'white' && props.theme === 'black')
      ? '500'
      : props.darknessBackground,
    (!props.background && props.theme === 'black') || props.background === 'white' ? '500' : props.darknessBackground,
  ),
);
const fontSize = computed(() => {
@@ -36,6 +35,13 @@ const fontSize = computed(() => {
  if (size === 'huge') return '24px';
  return '12px';
});
const padding = computed(() => {
  const size = props.size;
  if (size === 'normal') return '6px';
  if (size === 'large') return '10px';
  if (size === 'huge') return '14px';
  return '4px';
});

const pickOption = (value: string) => {
  selected.value = value;
@@ -54,38 +60,31 @@ const calcOptionColor = (color: TThemeColor | undefined, darknessColor: string |
      </option>
    </select>
    <div class="list" :style="`background-color: ${backgroundColor}`">
      <button @click.prevent="isOpen = !isOpen" class="button" :style="`width: ${width}`">
        <span
      <button
        @click.prevent="!disabled ? (isOpen = !isOpen) : ''"
        :class="[
          'button',
          {
            disabled: disabled,
          },
        ]"
        :style="`width: ${width}`"
      >
        <SelectItem
          class="selected"
          :style="`color: ${selected ? calcOptionColor(selectedOption?.color, selectedOption?.darknessColor, textColor) : '#62708c'}; font-weight: 600`"
          :style="`color: ${selected ? calcOptionColor(selectedOption?.color, selectedOption?.darknessColor, textColor) : placeholderColor ? convertThemeToColor(placeholderColor, '700') : '#62708c'}; font-weight: 600`"
          :option="selectedOption"
          :fontSize="fontSize"
          :textColor="textColor"
        >
          <slot :name="`icon-left-${selectedOption?.value}`"></slot>
          <span :style="`font-size: ${fontSize}`">{{ selected ?? placeholder }}</span>
          <slot :name="`icon-right-${selectedOption?.value}`"></slot>
        </SelectItem>
        <component
            v-if="selectedOption?.iconLeft"
            :is="iconsSet[selectedOption?.iconLeft]"
            :size="fontSize.slice(0, -2)"
            :color="
              calcOptionColor(
                selectedOption.iconColor ?? selectedOption?.color,
                selectedOption?.darknessColor,
                textColor,
              )
            " /><span>{{ selected ?? placeholder }}</span>
          <component
            v-if="selectedOption?.iconRight"
            :is="iconsSet[selectedOption?.iconRight]"
            :size="fontSize.slice(0, -2)"
            :color="
              calcOptionColor(
                selectedOption.iconColor ?? selectedOption?.color,
                selectedOption?.darknessColor,
                textColor,
              )
            " /><slot :name="`icon-right-${selectedOption?.value}`"></slot></span
        ><component
          :is="iconsSet[openIcon]"
          :size="fontSize.slice(0, -2)"
          color="#62708c"
          :color="openIconColor ? convertThemeToColor(openIconColor, darknessOpenIcon) : '#62708c'"
          :style="`width: ${fontSize}`"
        />
      </button>
@@ -98,7 +97,7 @@ const calcOptionColor = (color: TThemeColor | undefined, darknessColor: string |
        ]"
      >
        <div style="overflow: hidden">
          <p
          <SelectItem
            @click.prevent="pickOption(option.value)"
            v-for="option of options"
            :key="option.value"
@@ -111,22 +110,14 @@ const calcOptionColor = (color: TThemeColor | undefined, darknessColor: string |
            ]"
            :style="`color: ${calcOptionColor(option.color, option.darknessColor, textColor)};
            background-color: ${calcOptionColor(option.background, option.darknessBackground, backgroundColor)}`"
            :option="option"
            :fontSize="fontSize"
            :textColor="textColor"
          >
            <slot :name="`icon-left-${option.value}`"></slot>
            <component
              v-if="option.iconLeft"
              :is="iconsSet[option.iconLeft]"
              :size="fontSize.slice(0, -2)"
              :color="calcOptionColor(option.iconColor ?? option.color, option.darknessColor, textColor)"
            /><span>{{ option.label ?? option.value }}</span
            ><component
              v-if="option.iconRight"
              :is="iconsSet[option.iconRight]"
              :size="fontSize.slice(0, -2)"
              :color="calcOptionColor(option.iconColor ?? option.color, option.darknessColor, textColor)"
            />
            <span :style="`font-size: ${fontSize}`">{{ option.label ?? option.value }}</span>
            <slot :name="`icon-right-${option.value}`"></slot>
          </p>
          </SelectItem>
        </div>
      </div>
    </div>
@@ -146,7 +137,7 @@ const calcOptionColor = (color: TThemeColor | undefined, darknessColor: string |
}
.button {
  display: flex;
  padding: 7px;
  padding: v-bind(padding);
  justify-content: space-between;
  gap: 10px;
}
@@ -176,7 +167,7 @@ const calcOptionColor = (color: TThemeColor | undefined, darknessColor: string |
  display: flex;
  align-items: center;
  gap: 5px;
  padding: 7px;
  padding: v-bind(padding);
}
.option:hover {
  filter: brightness(90%);
@@ -193,36 +184,9 @@ const calcOptionColor = (color: TThemeColor | undefined, darknessColor: string |
  border-bottom-right-radius: 4px;
  border-bottom-left-radius: 4px;
}
.disabled {
  cursor: auto;
  background-color: #e1e7f1 !important;
  border-radius: 4px;
}
</style>
<!--.list {-->
<!--position: relative;-->
<!--width: max-content;-->
<!--border: 1px solid v-bind(textColor);-->
<!--border-radius: 5px 5px 0 0;-->
<!--cursor: pointer;-->
<!--}-->
<!--.button {-->
<!--display: flex;-->
<!--padding: 7px;-->
<!--justify-content: space-between;-->
<!--gap: 10px;-->
<!--}-->
<!--.selected {-->
<!--display: flex;-->
<!--gap: 5px;-->
<!--}-->
<!--.options {-->
<!--position: absolute;-->
<!--top: 100%;-->
<!--width: 100%;-->
<!--border: 1px solid v-bind(textColor);-->
<!--border-top: none;-->
<!--border-bottom-left-radius: 5px;-->
<!--border-bottom-right-radius: 5px;-->
<!--display: grid;-->
<!--grid-template-rows: 0fr;-->
<!--opacity: 0;-->
<!--transition:-->
<!--all 0.2s ease-in-out,-->
<!--opacity 0.1s ease-in-out;-->
<!--}-->
Loading