Skip to content

feat(components): add ui field in items #4060

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

Draft
wants to merge 56 commits into
base: v3
Choose a base branch
from

Conversation

J-Michalek
Copy link

@J-Michalek J-Michalek commented May 4, 2025

πŸ”— Linked issue

Resolves: #4059

❓ Type of change

  • πŸ“– Documentation (updates to the documentation or readme)
  • 🐞 Bug fix (a non-breaking change that fixes an issue)
  • πŸ‘Œ Enhancement (improving an existing functionality)
  • ✨ New feature (a non-breaking change that adds functionality)
  • 🧹 Chore (updates to the build process or auxiliary tools and libraries)
  • ⚠️ Breaking change (fix or feature that would cause existing functionality to change)

πŸ“š Description

I have added the ui field in items array - this affects all components that currently use an items prop.

This will simplify cases where the user wants to use a specific classes for different parts of an item but does not want affect other items at the same time.

Edit:

πŸ“ Checklist

  • I have linked an issue or discussion.
  • I have updated the documentation accordingly.

Copy link

pkg-pr-new bot commented May 4, 2025

npm i https://pkg.pr.new/@nuxt/ui@4060

commit: 9a7309a

@benjamincanac
Copy link
Member

I agree this is a nice addition! However, this change should be applied to all components with an items prop for consistency 😬

@J-Michalek
Copy link
Author

@benjamincanac I can work on this. Should I bunch it up into a one big PR or should I create separate PR for each instance?

@benjamincanac
Copy link
Member

Great! No you can do this in this PR 😊

@J-Michalek J-Michalek changed the title feat(stepper): add iconClass prop to stepper items feat(items): add iconClass prop to items May 5, 2025
@benjamincanac benjamincanac changed the title feat(items): add iconClass prop to items feat(components): add iconClass field in items May 5, 2025
@J-Michalek
Copy link
Author

J-Michalek commented May 5, 2025

Quick checklist to track the progress on this (I will validate it as I go through it):

  • Accordion
  • Tabs
  • Stepper
  • Carousel
  • Breadcrumb
  • CheckboxGroup
  • RadioGroup
  • InputMenu
  • Tree
  • Select
  • SelectMenu
  • NavigationMenu - here we could support different ui fields for NavigationMenuItem and NavigationMenuChildItem but that would required some refactoring of the component, perhaps in another iteration.
  • DropdownMenu
  • ContextMenu

@benjamincanac benjamincanac marked this pull request as draft May 5, 2025 15:44
@J-Michalek
Copy link
Author

J-Michalek commented May 5, 2025

@benjamincanac Just one more idea, what if we added a ui prop to the item interface that would allow customization of each part of the item but on a per item basis.

i.e. for the Accordion each item could have a ui prop that would contain the slots that affect the item specifically:

<AccordionItem
      v-for="(item, index) in props.items"
      v-slot="{ open }"
      :key="index"
      :value="item.value || String(index)"
      :disabled="item.disabled"
      :class="ui.item({ class: [props.ui?.item, item.ui?.item] })"
    >
      <AccordionHeader as="div" :class="ui.header({ class: [props.ui?.header, item.ui?.header] })">
        <AccordionTrigger :class="ui.trigger({ class: [props.ui?.trigger, item.ui?.trigger], disabled: item.disabled })">
          <slot name="leading" :item="item" :index="index" :open="open">
            <UIcon v-if="item.icon" :name="item.icon" :class="ui.leadingIcon({ class: [props.ui?.leadingIcon, item?.ui?.leadingIcon] })" />
          </slot>

          <span v-if="get(item, props.labelKey as string) || !!slots.default" :class="ui.label({ class: [props.ui?.label, item.ui?.label] })">
            <slot :item="item" :index="index" :open="open">{{ get(item, props.labelKey as string) }}</slot>
          </span>

          <slot name="trailing" :item="item" :index="index" :open="open">
            <UIcon :name="item.trailingIcon || trailingIcon || appConfig.ui.icons.chevronDown" :class="ui.trailingIcon({ class: [props.ui?.trailingIcon, item.ui?.trailingIcon] })" />
          </slot>
        </AccordionTrigger>
      </AccordionHeader>

      <AccordionContent v-if="item.content || !!slots.content || (item.slot && !!slots[item.slot as keyof AccordionSlots<T>]) || !!slots.body || (item.slot && !!slots[`${item.slot}-body` as keyof AccordionSlots<T>])" :class="ui.content({ class: [props.ui?.content, item.ui?.content] })">
        <slot :name="((item.slot || 'content') as keyof AccordionSlots<T>)" :item="(item as Extract<T, { slot: string; }>)" :index="index" :open="open">
          <div :class="ui.body({ class: [props.ui?.body, item.ui?.body] })">
            <slot :name="((item.slot ? `${item.slot}-body`: 'body') as keyof AccordionSlots<T>)" :item="(item as Extract<T, { slot: string; }>)" :index="index" :open="open">
              {{ item.content }}
            </slot>
          </div>
        </slot>
      </AccordionContent>
    </AccordionItem>

I feel like it would be more future proof as everyone might have different needs of per item customization, of course this is more involved solution but I think it might be worth it.

@benjamincanac
Copy link
Member

We could uniformize this as well indeed, I did it in very specific places where I needed to make an example only at the moment: https://github.com/nuxt/ui/blob/v3/src/runtime/components/Select.vue#L243

@J-Michalek
Copy link
Author

@benjamincanac Here is a quick commit for the accordion component, if you could quickly have a look if I'm going in the right direction with this.

@J-Michalek J-Michalek changed the title feat(components): add iconClass field in items feat(components): add ui field in items May 6, 2025
Jakub and others added 29 commits May 7, 2025 19:29
@J-Michalek
Copy link
Author

@benjamincanac I think I'm done with this. I have updated the PR description above.

Two things worth mentioning:

  • I had to change the type of carousel items a bit, see 2a270ea
  • NavigationMenu is a bit more complicated because it has another array of nested items which would need different type for the ui field and we would need to differentiate between top level and child items in the template, for now I just implemented the ui field for the top level items and omitted it from the NavigationMenuChildItem interface, see 1214fcb#diff-c7d773da155e1f06395d05bef2ab7ad26a66ca1af0de932ddf88350acfc16a08R11

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment
Labels
v3 #1289
Projects
None yet
Development

Successfully merging this pull request may close these issues.

Stepper: Add class for each step's icon
2 participants