Skip to content

Commit

Permalink
fix(Menu): class is now reactive along with child components
Browse files Browse the repository at this point in the history
fix(Menu): changed properties to make active item more simple
docs(menu): added examples, props, and slots tables
docs(Navigation): refactored due to Menu changes
  • Loading branch information
Craig Howell authored and Craig Howell committed Oct 11, 2022
1 parent 34b31ab commit b49b057
Show file tree
Hide file tree
Showing 8 changed files with 460 additions and 227 deletions.
45 changes: 18 additions & 27 deletions src/docs/components/navigation/Navigation.svelte
Original file line number Diff line number Diff line change
@@ -1,6 +1,7 @@
<script lang="ts">
import { Badge, Menu } from '../../../lib';
import { page } from '$app/stores';
import { onMount } from 'svelte/internal';
const sidebarItems = [
{
Expand Down Expand Up @@ -164,67 +165,57 @@
}
];
export let selected: string | undefined = undefined;
export let collapsed = false;
export let handleClose: (() => void) | undefined = undefined;
function handleClick() {
let active = '';
function handleClick(item: string) {
active = item;
if (handleClose) {
handleClose();
}
}
$: if ($page) {
setActiveItems();
}
function setActiveItems() {
let path = $page.url.pathname;
path = path.substring(1);
const pathArray = path.split('-');
let tempSelected = '';
for (const a of pathArray) {
tempSelected += a.charAt(0).toUpperCase() + a.slice(1);
}
selected = tempSelected;
}
onMount(() => {
active = $page.url.pathname;
});
</script>

<h3
class="text-xs font-bold text-light-content dark:text-dark-content text-opacity-40 dark:text-opacity-40 mb-2"
>
GET STARTED
</h3>
<Menu {collapsed} showActiveByURL={false}>
<Menu {active}>
<Menu.Item
key="/installation"
label="Installation"
href="/installation"
active={selected === 'Installation'}
on:click={handleClick}
on:click={() => handleClick('/installation')}
/>
</Menu>
<h3
class="text-xs font-bold text-light-content dark:text-dark-content text-opacity-40 dark:text-opacity-40 mb-2 mt-4"
>
COMPONENTS
</h3>
<Menu {collapsed} showActiveByURL={false}>
<Menu {active}>
{#each sidebarItems as item}
{#if item.beta}
<Menu.Item
key={item.href}
label={item.title}
href={item.href}
active={selected === item.title}
on:click={handleClick}
on:click={() => handleClick(item.href)}
>
<Badge slot="extra" type="error">BETA</Badge>
</Menu.Item>
{:else}
<Menu.Item
key={item.href}
label={item.title}
href={item.href}
active={selected === item.title}
on:click={handleClick}
on:click={() => handleClick(item.href)}
/>
{/if}
{/each}
Expand All @@ -234,6 +225,6 @@
>
TYPES
</h3>
<Menu {collapsed} showActiveByURL={false}>
<Menu.Item label="Types" href="/types" active={selected === 'Types'} on:click={handleClick} />
<Menu {active}>
<Menu.Item key="/types" label="Types" href="/types" on:click={() => handleClick('/types')} />
</Menu>
69 changes: 34 additions & 35 deletions src/lib/components/menu/Group.svelte
Original file line number Diff line number Diff line change
@@ -1,34 +1,50 @@
<script lang="ts" context="module">
export const MENU_GROUP_CONTEXT_ID = 'menu-group-context-id';
</script>

<script lang="ts">
import { page } from '$app/stores';
import HoverBackground from '../HoverBackground.svelte';
import { slide, scale, type TransitionConfig } from 'svelte/transition';
import { getContext } from 'svelte';
import { getContext, setContext } from 'svelte';
import type { Writable } from 'svelte/store';
import { MENU_CONTEXT_ID } from './Menu.svelte';
import { useContext } from '$lib/utils/useContext';
import { twMerge } from 'tailwind-merge';
export let label: string;
export let href: string;
export let key: string;
let active = false;
let menuActive = false;
let collapsable: HTMLDivElement;
useContext({
context_id: MENU_CONTEXT_ID,
parent: 'Menu',
component: 'Menu.Group'
});
setContext(MENU_GROUP_CONTEXT_ID, {
group: true,
groupKey: key
});
const {
menuCollapse,
showActiveByURL
activeItem
}: {
menuCollapse: Writable<boolean>;
showActiveByURL: boolean;
activeItem: Writable<string>;
} = getContext(MENU_CONTEXT_ID);
$: menuActive = $activeItem.includes(key);
let forceCollapse = $menuCollapse ? true : false;
$: if ($menuCollapse) {
forceCollapse = true;
active = false;
}
function toggleOpen(href: string, e: Event) {
function toggleOpen(e: Event) {
if ($menuCollapse) {
if (collapsable === e.target) {
active = false;
Expand Down Expand Up @@ -59,37 +75,18 @@
}
}
useContext({
context_id: MENU_CONTEXT_ID,
parent: 'Menu',
component: 'Menu.Group'
});
if (showActiveByURL) {
setActiveItems();
}
$: if (showActiveByURL && $page) {
setActiveItems();
}
function setActiveItems() {
if ($page.url.pathname.includes(href) || $page.url.hash.includes(href)) {
menuActive = true;
} else {
menuActive = false;
}
}
let defaultClass = 'transition-all duration-300';
$: finalClass = twMerge(defaultClass, $$props.class);
</script>

<div
bind:this={collapsable}
class="relative w-full"
on:mouseover={$menuCollapse ? (e) => toggleOpen(href, e) : undefined}
on:focus={$menuCollapse ? (e) => toggleOpen(href, e) : undefined}
on:mouseleave={$menuCollapse ? (e) => toggleOpen(href, e) : undefined}
on:mouseover={$menuCollapse ? toggleOpen : undefined}
on:focus={$menuCollapse ? toggleOpen : undefined}
on:mouseleave={$menuCollapse ? toggleOpen : undefined}
>
<div class="transition-all duration-300" style="width: {$menuCollapse ? '3rem' : '100%'}">
<div class={finalClass} style={$$props.style}>
<h2
class="group relative m-0 w-full outline-none rounded-md focus:outline-none overflow-hidden"
class:text-light-content={active}
Expand All @@ -98,11 +95,13 @@
class:dark:text-dark-secondary-content={!active}
class:hover:text-light-content={!active}
class:dark:hover:text-dark-content={!active}
class:bg-light-icon-background-hover={$menuCollapse && menuActive}
class:dark:bg-dark-icon-background-hover={$menuCollapse && menuActive}
class:bg-light-icon-background-hover={($menuCollapse && menuActive) ||
(!$menuCollapse && !active && menuActive)}
class:dark:bg-dark-icon-background-hover={($menuCollapse && menuActive) ||
(!$menuCollapse && !active && menuActive)}
>
<button
on:click={!$menuCollapse ? (e) => toggleOpen(href, e) : undefined}
on:click={!$menuCollapse ? toggleOpen : undefined}
class="px-3 py-2 relative flex items-center w-full text-sm font-medium justify-between outline-none focus:outline-none"
type="button"
>
Expand Down
48 changes: 28 additions & 20 deletions src/lib/components/menu/GroupItem.svelte
Original file line number Diff line number Diff line change
@@ -1,42 +1,49 @@
<script lang="ts">
import { page } from '$app/stores';
import HoverBackground from '../HoverBackground.svelte';
import { getContext } from 'svelte';
import { MENU_CONTEXT_ID } from './Menu.svelte';
import { MENU_GROUP_CONTEXT_ID } from './Group.svelte';
import type { Writable } from 'svelte/store';
import { twMerge } from 'tailwind-merge';
import { useContext } from '$lib/utils/useContext';
export let href: string;
export let label: string;
export let active = false;
export let key: string;
useContext({
context_id: MENU_CONTEXT_ID,
parent: 'Menu',
component: 'Menu.Group.Item'
});
useContext({
context_id: MENU_GROUP_CONTEXT_ID,
parent: 'Menu.Group',
component: 'Menu.Group.Item'
});
const {
menuCollapse,
showActiveByURL
activeItem
}: {
menuCollapse: Writable<boolean>;
showActiveByURL: boolean;
activeItem: Writable<string>;
} = getContext(MENU_CONTEXT_ID);
if (showActiveByURL) {
setActiveItems();
}
$: if (showActiveByURL && $page) {
setActiveItems();
}
function setActiveItems() {
if ($page.url.pathname.includes(href) || $page.url.hash.includes(href)) {
active = true;
} else {
active = false;
}
}
const { groupKey }: { groupKey: string } = getContext(MENU_GROUP_CONTEXT_ID);
$: active = $activeItem === `${groupKey}-${key}`;
const defaultClass =
'group relative flex items-center min-w-full h-10 px-3 py-2 text-sm font-medium rounded-md';
$: finalClass = twMerge(defaultClass, $$props.class);
</script>

<a
on:click
{href}
class="group relative flex items-center min-w-full h-10 px-3 py-2 text-sm font-medium rounded-md"
class={finalClass}
class:text-light-content={active}
class:dark:text-dark-content={active}
class:text-light-secondary-content={!active}
Expand All @@ -45,6 +52,7 @@
class:dark:hover:text-dark-content={!active}
class:bg-light-icon-background-hover={active}
class:dark:bg-dark-icon-background-hover={active}
style={$$props.style}
>
{#if !$menuCollapse}
<span class="w-6 mr-2" />
Expand Down
2 changes: 1 addition & 1 deletion src/lib/components/menu/Icon.svelte
Original file line number Diff line number Diff line change
Expand Up @@ -5,7 +5,7 @@
export let icon: MaterialIcon;
const defaultClass = 'material-icons h-6 w-6 min-h-6 min-w-6 mr-3';
const finalClass = twMerge(defaultClass, $$props.class);
$: finalClass = twMerge(defaultClass, $$props.class);
</script>

<span class={finalClass} style={$$props.style}>{icon}</span>
27 changes: 8 additions & 19 deletions src/lib/components/menu/Item.svelte
Original file line number Diff line number Diff line change
@@ -1,41 +1,30 @@
<script lang="ts">
import { page } from '$app/stores';
import { tooltip } from '../../actions';
import HoverBackground from '../HoverBackground.svelte';
import { getContext } from 'svelte';
import type { Writable } from 'svelte/store';
import { MENU_CONTEXT_ID } from './Menu.svelte';
import { twMerge } from 'tailwind-merge';
export let label: string;
export let href: string;
export let active = false;
export let key: string;
const {
menuCollapse,
showActiveByURL
activeItem
}: {
menuCollapse: Writable<boolean>;
showActiveByURL: boolean;
activeItem: Writable<string>;
} = getContext(MENU_CONTEXT_ID);
if (showActiveByURL) {
setActiveItems();
}
$: active = $activeItem === key;
$: if (showActiveByURL && $page) {
setActiveItems();
}
function setActiveItems() {
if ($page.url.pathname.includes(href) || $page.url.hash.includes(href)) {
active = true;
} else {
active = false;
}
}
let defaultClass = 'transition-all duration-300';
$: finalClass = twMerge(defaultClass, $$props.class);
</script>

<div class="transition-all duration-300" style="width: {$menuCollapse ? '3rem' : '100%'}">
<div class={finalClass} style={$$props.style}>
<a
on:click
use:tooltip={{
Expand Down
22 changes: 18 additions & 4 deletions src/lib/components/menu/Menu.svelte
Original file line number Diff line number Diff line change
Expand Up @@ -5,20 +5,34 @@
<script lang="ts">
import { setContext } from 'svelte';
import { writable } from 'svelte/store';
export let showActiveByURL = true;
import { twMerge } from 'tailwind-merge';
export let collapsed = false;
export let collapsedWidth = 'w-12';
export let active = '';
let menuCollapse = writable(collapsed);
$: menuCollapse.set(collapsed);
let activeItem = writable(active);
$: activeItem.set(active);
setContext(MENU_CONTEXT_ID, {
menu: true,
menuCollapse,
showActiveByURL
collapsedWidth,
activeItem
});
let defaultClass = 'space-y-1 transition-all duration-300';
$: if ($menuCollapse) {
defaultClass = defaultClass + ' ' + collapsedWidth;
} else {
defaultClass = defaultClass + ' w-full';
}
$: finalClass = twMerge(defaultClass, $$props.class);
</script>

<nav class="space-y-1 transition-all duration-300" style="width: {collapsed ? '3rem' : '100%'}">
<nav class={finalClass} style={$$props.style}>
<slot />
</nav>
Loading

0 comments on commit b49b057

Please sign in to comment.