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

Drop actions in favor of onBrowserMount #15

Merged
merged 41 commits into from
Jul 6, 2023
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
Show all changes
41 commits
Select commit Hold shift + click to select a range
bb65895
fix: parent submenu closes because of rerender
ubermanu Jun 21, 2023
482787c
use menu in docs sidebar
ubermanu Jun 21, 2023
c984bd9
implement onBrowserMount on collapsible to get rid of the action
ubermanu Jun 29, 2023
895c937
rework tabs and implement missing ids
ubermanu Jun 29, 2023
8d16199
cleanup tabs
ubermanu Jun 29, 2023
ca9790d
update readme
ubermanu Jun 30, 2023
42b3cca
udate accordion
ubermanu Jun 30, 2023
7e635ca
use data attrs to target the root element
ubermanu Jun 30, 2023
26bcae0
remove switch action in favor of onMount
ubermanu Jun 30, 2023
df24c14
remove action on button
ubermanu Jun 30, 2023
e8da072
remove link action
ubermanu Jun 30, 2023
f6166c2
remove actions in popover
ubermanu Jun 30, 2023
d429585
remove radiogroup action
ubermanu Jun 30, 2023
76d24f8
remove tooltip action
ubermanu Jun 30, 2023
cfd8ee5
remove tagGroup action
ubermanu Jun 30, 2023
1404d0c
remove toggle button action
ubermanu Jun 30, 2023
ce39029
fix: remove action in switch example
ubermanu Jun 30, 2023
9554098
remove action from listbox and add multiple example
ubermanu Jun 30, 2023
6d875e1
avoid scrolling when setiing the 1st active desc
ubermanu Jun 30, 2023
52348f5
update listbox
ubermanu Jun 30, 2023
6d368ac
remove action from calendar component
ubermanu Jul 3, 2023
3584e23
remove actions from select
ubermanu Jul 3, 2023
cfddd71
remove actions from combobox
ubermanu Jul 4, 2023
0a1cccc
remove action from label
ubermanu Jul 4, 2023
6da5212
minor changes
ubermanu Jul 4, 2023
d11839a
remove action from toolbar
ubermanu Jul 4, 2023
135503a
tooltip component now runs floating ui by itself
ubermanu Jul 4, 2023
537a789
chore: format code
ubermanu Jul 4, 2023
1f88abf
feat: focus trap
ubermanu Jul 4, 2023
f0b4717
update docs
ubermanu Jul 4, 2023
1d24941
feat: update popover (trap focus and handles positioning)
ubermanu Jul 4, 2023
0f7cc92
Merge branch 'menu-improvements' into browser-mount
ubermanu Jul 4, 2023
c2147e8
feat: update menu component to handle properly submenus
ubermanu Jul 5, 2023
ce7fe82
chore: minor change
ubermanu Jul 5, 2023
14bed19
feat: remove checkbox action
ubermanu Jul 5, 2023
933b0ca
chore: remove dangling actions in button tests
ubermanu Jul 5, 2023
1759af4
feat: remove action from carousel component
ubermanu Jul 5, 2023
cf929c4
chore: remove already inferred types
ubermanu Jul 5, 2023
1b7ffca
fix: toggle btn tabindex
ubermanu Jul 5, 2023
b33efe7
fix: tests
ubermanu Jul 6, 2023
8bfdcfa
add space between button and popover content
ubermanu Jul 6, 2023
File filter

Filter by extension

Filter by extension


Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
4 changes: 2 additions & 2 deletions README.md
Original file line number Diff line number Diff line change
Expand Up @@ -17,11 +17,11 @@ npm install louisette
<script>
import { createCollapsible } from 'louisette'

const { trigger, triggerAttrs, contentAttrs } = createCollapsible()
const { triggerAttrs, contentAttrs } = createCollapsible()
</script>

<div>
<button use:trigger {...$triggerAttrs}>Toggle</button>
<button {...$triggerAttrs}>Toggle</button>
<div {...$contentAttrs}>
<p>Content</p>
</div>
Expand Down
5 changes: 4 additions & 1 deletion package.json
Original file line number Diff line number Diff line change
Expand Up @@ -43,7 +43,6 @@
},
"prettier": "@ubermanu/prettier-config",
"devDependencies": {
"@floating-ui/dom": "^1.2.9",
"@fontsource-variable/caveat": "^5.0.1",
"@sveltejs/adapter-auto": "^2.0.1",
"@sveltejs/adapter-static": "^2.0.2",
Expand Down Expand Up @@ -81,5 +80,9 @@
},
"peerDependencies": {
"svelte": "^3.54.0"
},
"dependencies": {
"@floating-ui/dom": "^1.4.3",
"focusable-selectors": "^0.8.0"
}
}
33 changes: 23 additions & 10 deletions pnpm-lock.yaml

Some generated files are not rendered by default. Learn more about how customized files appear on GitHub.

33 changes: 33 additions & 0 deletions src/lib/actions/FocusTrap/focusTrap.ts
Original file line number Diff line number Diff line change
@@ -0,0 +1,33 @@
import { getFocusableElements } from '$lib/helpers/dom.js'
import type { Action } from 'svelte/action'

export const focusTrap: Action = (node: HTMLElement) => {
const onKeyDown = (event: KeyboardEvent) => {
const focusableElements = getFocusableElements(node)

const firstFocusableElement = focusableElements[0]
const lastFocusableElement = focusableElements[focusableElements.length - 1]

if (event.key === 'Tab') {
if (event.shiftKey) {
if (document.activeElement === firstFocusableElement) {
event.preventDefault()
lastFocusableElement.focus()
}
} else {
if (document.activeElement === lastFocusableElement) {
event.preventDefault()
firstFocusableElement.focus()
}
}
}
}

node.addEventListener('keydown', onKeyDown, true)

return {
destroy() {
node.removeEventListener('keydown', onKeyDown, true)
},
}
}
58 changes: 30 additions & 28 deletions src/lib/components/Accordion/accordion.ts
Original file line number Diff line number Diff line change
@@ -1,9 +1,9 @@
import { onBrowserMount } from '$lib/helpers/environment.js'
import type { DelegateEvent } from '$lib/helpers/events.js'
import { delegateEventListeners } from '$lib/helpers/events.js'
import { traveller } from '$lib/helpers/traveller.js'
import { generateId } from '$lib/helpers/uuid.js'
import type { Action } from 'svelte/action'
import { derived, get, readonly, writable } from 'svelte/store'
import { derived, get, readable, readonly, writable } from 'svelte/store'
import type { Accordion, AccordionConfig } from './accordion.types.js'

export const createAccordion = (config?: AccordionConfig): Accordion => {
Expand All @@ -14,16 +14,20 @@ export const createAccordion = (config?: AccordionConfig): Accordion => {
const disabled$ = writable(disabled || [])

const baseId = generateId()
const getTriggerId = (key: string) => `${baseId}-trigger-${key}`
const getContentId = (key: string) => `${baseId}-content-${key}`
const triggerId = (key: string) => `${baseId}-trigger-${key}`
const contentId = (key: string) => `${baseId}-content-${key}`

const rootAttrs = readable({
'data-accordion': baseId,
})

const triggerAttrs = derived(
[expanded$, disabled$],
([expanded, disabled]) => {
return (key: string) => ({
id: getTriggerId(key),
id: triggerId(key),
role: 'button',
'aria-controls': getContentId(key),
'aria-controls': contentId(key),
'aria-expanded': expanded.includes(key),
'aria-disabled': disabled.includes(key),
tabIndex: disabled.includes(key) ? -1 : 0,
Expand All @@ -35,9 +39,9 @@ export const createAccordion = (config?: AccordionConfig): Accordion => {

const contentAttrs = derived([expanded$], ([expanded]) => {
return (key: string) => ({
id: getContentId(key),
id: contentId(key),
role: 'region',
'aria-labelledby': getTriggerId(key),
'aria-labelledby': triggerId(key),
'aria-hidden': !expanded.includes(key),
inert: !expanded.includes(key) ? '' : undefined,
'data-accordion-content': key,
Expand Down Expand Up @@ -113,7 +117,7 @@ export const createAccordion = (config?: AccordionConfig): Accordion => {
/** Toggles the accordion when the trigger is clicked. */
const onTriggerClick = (event: DelegateEvent<MouseEvent>) => {
event.preventDefault()
toggle(event.delegateTarget.dataset.accordionTrigger as string)
toggle(event.delegateTarget.dataset.accordionTrigger!)
}

/**
Expand All @@ -128,7 +132,7 @@ export const createAccordion = (config?: AccordionConfig): Accordion => {
*/
const onTriggerKeyDown = (event: DelegateEvent<KeyboardEvent>) => {
const target = event.delegateTarget
const key = target.dataset.accordionTrigger as string
const key = target.dataset.accordionTrigger!

if (event.key === 'Enter' || event.key === ' ') {
event.preventDefault()
Expand All @@ -140,15 +144,10 @@ export const createAccordion = (config?: AccordionConfig): Accordion => {
collapse(key)
}

if (!rootNode) {
console.warn('The accordion root node is not defined.')
return
}

const $disabled = get(disabled$)

const nodes = traveller(rootNode, '[data-accordion-trigger]', (el) => {
return $disabled.includes(el.dataset.accordionTrigger as string)
const nodes = traveller(rootNode!, '[data-accordion-trigger]', (el) => {
return $disabled.includes(el.dataset.accordionTrigger!)
})

if (event.key === 'ArrowUp') {
Expand All @@ -172,11 +171,16 @@ export const createAccordion = (config?: AccordionConfig): Accordion => {
}
}

/** Bind event listeners to the accordion */
const useAccordion: Action = (node) => {
rootNode = node
onBrowserMount(() => {
rootNode = document.querySelector<HTMLElement>(
`[data-accordion="${baseId}"]`
)

const removeListeners = delegateEventListeners(node, {
if (!rootNode) {
throw new Error('No root node found for the accordion')
}

const removeListeners = delegateEventListeners(rootNode, {
keydown: {
'[data-accordion-trigger]': onTriggerKeyDown,
},
Expand All @@ -192,21 +196,19 @@ export const createAccordion = (config?: AccordionConfig): Accordion => {
}
})

return {
destroy() {
removeListeners()
unsubscribe()
},
return () => {
removeListeners()
unsubscribe()
}
}
})

return {
multiple: multiple$,
expanded: readonly(expanded$),
disabled: readonly(disabled$),
rootAttrs,
triggerAttrs,
contentAttrs,
accordion: useAccordion,
expand,
collapse,
toggle,
Expand Down
3 changes: 1 addition & 2 deletions src/lib/components/Accordion/accordion.types.ts
Original file line number Diff line number Diff line change
@@ -1,5 +1,4 @@
import type { HTMLAttributes } from '$lib/helpers/types.js'
import type { Action } from 'svelte/action'
import type { Readable } from 'svelte/store'

export type AccordionConfig = {
Expand All @@ -12,9 +11,9 @@ export type Accordion = {
multiple: Readable<boolean>
expanded: Readable<string[]>
disabled: Readable<string[]>
rootAttrs: Readable<HTMLAttributes>
triggerAttrs: Readable<(key: string) => HTMLAttributes>
contentAttrs: Readable<(key: string) => HTMLAttributes>
accordion: Action
expand: (key: string) => void
collapse: (key: string) => void
toggle: (key: string) => void
Expand Down
4 changes: 2 additions & 2 deletions src/lib/components/Accordion/example/Accordion.svelte
Original file line number Diff line number Diff line change
Expand Up @@ -2,10 +2,10 @@
import { createAccordion } from '$lib'
import { setContext } from 'svelte'

const { accordion, ...accordionContext } = createAccordion()
const { rootAttrs, ...accordionContext } = createAccordion()
setContext('accordion', accordionContext)
</script>

<div use:accordion>
<div {...$rootAttrs}>
<slot />
</div>
4 changes: 2 additions & 2 deletions src/lib/components/Accordion/tests/Accordion.test.svelte
Original file line number Diff line number Diff line change
Expand Up @@ -4,10 +4,10 @@
export let items: { id: number; label: string; content: string }[] = []
export let defaults = {}

const { accordion, triggerAttrs, contentAttrs } = createAccordion(defaults)
const { rootAttrs, triggerAttrs, contentAttrs } = createAccordion(defaults)
</script>

<div data-testid="accordion" use:accordion>
<div data-testid="accordion" {...$rootAttrs}>
{#each items as item}
<div data-testid="accordion-item-{item.id}">
<div
Expand Down
27 changes: 18 additions & 9 deletions src/lib/components/Button/button.ts
Original file line number Diff line number Diff line change
@@ -1,4 +1,5 @@
import type { Action } from 'svelte/action'
import { onBrowserMount } from '$lib/helpers/environment.js'
import { generateId } from '$lib/helpers/uuid.js'
import { derived, get, writable } from 'svelte/store'
import type { Button, ButtonConfig } from './button.types.js'

Expand All @@ -7,10 +8,13 @@ export const createButton = (config?: ButtonConfig): Button => {

const disabled$ = writable(disabled || false)

const baseId = generateId()

const buttonAttrs = derived([disabled$], ([disabled]) => ({
role: 'button',
'aria-disabled': disabled,
tabIndex: disabled ? -1 : 0,
'data-button': baseId,
}))

const onButtonClick = (event: MouseEvent) => {
Expand All @@ -27,21 +31,26 @@ export const createButton = (config?: ButtonConfig): Button => {
}
}

const useButton: Action = (node) => {
onBrowserMount(() => {
const node = document.querySelector<HTMLElement>(
`[data-button="${baseId}"]`
)

if (!node) {
throw new Error('Could not find the button')
}

node.addEventListener('click', onButtonClick)
node.addEventListener('keydown', onButtonKeyDown)

return {
destroy() {
node.removeEventListener('click', onButtonClick)
node.removeEventListener('keydown', onButtonKeyDown)
},
return () => {
node.removeEventListener('click', onButtonClick)
node.removeEventListener('keydown', onButtonKeyDown)
}
}
})

return {
disabled: disabled$,
buttonAttrs,
button: useButton,
}
}
6 changes: 2 additions & 4 deletions src/lib/components/Button/button.types.ts
Original file line number Diff line number Diff line change
@@ -1,13 +1,11 @@
import type { HTMLAttributes } from '$lib/helpers/types.js'
import type { Action } from 'svelte/action'
import type { Readable } from 'svelte/store'
import type { Readable, Writable } from 'svelte/store'

export type ButtonConfig = {
disabled?: boolean
}

export type Button = {
disabled: Readable<boolean>
disabled: Writable<boolean>
buttonAttrs: Readable<HTMLAttributes>
button: Action
}
3 changes: 1 addition & 2 deletions src/lib/components/Button/example/Button.svelte
Original file line number Diff line number Diff line change
@@ -1,11 +1,10 @@
<script lang="ts">
import { createButton } from '$lib'

const { button, buttonAttrs } = createButton()
const { buttonAttrs } = createButton()
</script>

<div
use:button
{...$buttonAttrs}
class="inline-flex w-auto select-none items-center rounded-md border border-transparent bg-accent-500 px-4 py-2 text-base font-medium text-white shadow-sm transition duration-150 ease-in-out hover:bg-accent-400 focus:outline-none focus-visible:ring focus-visible:ring-accent-500 focus-visible:ring-opacity-50 active:bg-accent-700 active:shadow-inner"
on:click
Expand Down
4 changes: 2 additions & 2 deletions src/lib/components/Button/tests/Button.test.svelte
Original file line number Diff line number Diff line change
Expand Up @@ -3,7 +3,7 @@

export let defaults = {}

const { button, buttonAttrs } = createButton(defaults)
const { buttonAttrs } = createButton(defaults)
</script>

<div data-testid="button" use:button {...$buttonAttrs}>Button</div>
<div data-testid="button" {...$buttonAttrs}>Button</div>
Loading