Skip to content
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
Show all changes
26 commits
Select commit Hold shift + click to select a range
bc0863e
Clean up (#2)
dedalik Jan 17, 2024
b2384fc
Change documentation app (#3)
dedalik Jan 22, 2024
8359103
Fix sub page sidebar (#4)
dedalik Jan 26, 2024
3517676
docs(functions): add copy-paste docs for expanded hook library
dedalik Apr 23, 2026
5e317e3
chore(deps): refresh docs lockfile metadata
dedalik Apr 23, 2026
d642607
docs(theme): add global import optimization guide across docs
dedalik Apr 23, 2026
f54bdd6
Improve docs (#5)
dedalik Apr 23, 2026
9f7c5bf
ci: Node 24 with checkout@v5 and setup-node@v5
dedalik Apr 23, 2026
a22c690
docs: add descriptive README for the documentation site
dedalik Apr 23, 2026
f058779
docs(readme): add API snapshot and sync guide for v1.1.0 (#6)
dedalik Apr 25, 2026
7da3fd6
Add GitHub Sponsors username to FUNDING.yml
dedalik Apr 25, 2026
c230e75
chore(release): v1.1.1 (#7)
dedalik Apr 26, 2026
6b15117
docs(elements): add live demo for useTextareaAutoSize
dedalik Apr 27, 2026
19a066d
docs(elements): add live demos for useClickOutside and useDraggable
dedalik Apr 27, 2026
6a585fe
docs(elements): add live demo for useElementSize
dedalik Apr 27, 2026
d357bc3
docs(elements): add live demo for useElementBounding
dedalik Apr 27, 2026
16344cf
docs(elements): add live demo for useElementVisibility
dedalik Apr 27, 2026
8a3eb51
docs(elements): add live demo for useParentElement
dedalik Apr 27, 2026
1892739
docs(elements): add live demo for useWindowFocus
dedalik Apr 27, 2026
4251d5a
docs(elements): add live demo for useWindowScroll
dedalik Apr 27, 2026
a70539a
docs(elements): add live demo for useActiveElement
dedalik Apr 27, 2026
6f35e16
docs(elements): add live demo for useDropZone
dedalik Apr 27, 2026
6fc0a8a
docs(oss): add home Elements showcase and clean local artifacts
dedalik Apr 27, 2026
8acd046
docs(demos): replace em dash with hyphen
dedalik Apr 27, 2026
58bea38
merge origin/main into add-demos
dedalik Apr 27, 2026
b42e528
style(docs): apply prettier formatting fixes
dedalik Apr 27, 2026
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
3 changes: 3 additions & 0 deletions .gitignore
Original file line number Diff line number Diff line change
@@ -1,9 +1,12 @@
.idea
.vscode
.cursor
node_modules
docs/.vitepress/cache/
docs/.vitepress/**/deps_temp_*/
dist
.DS_Store
.temp
.env
.env.*
*.log
14 changes: 14 additions & 0 deletions docs/.vitepress/data/homeElementsDemos.ts
Original file line number Diff line number Diff line change
@@ -0,0 +1,14 @@
/** Live demos for the home "Elements" section (same order as /functions/elements). */
export const homeElementsDemos: ReadonlyArray<{ demo: string; title: string }> = [
{ demo: 'useTextareaAutoSize/basic', title: 'useTextareaAutoSize' },
{ demo: 'useClickOutside/basic', title: 'useClickOutside' },
{ demo: 'useDraggable/basic', title: 'useDraggable' },
{ demo: 'useElementSize/basic', title: 'useElementSize' },
{ demo: 'useElementBounding/basic', title: 'useElementBounding' },
{ demo: 'useElementVisibility/basic', title: 'useElementVisibility' },
{ demo: 'useParentElement/basic', title: 'useParentElement' },
{ demo: 'useWindowFocus/basic', title: 'useWindowFocus' },
{ demo: 'useWindowScroll/basic', title: 'useWindowScroll' },
{ demo: 'useActiveElement/basic', title: 'useActiveElement' },
{ demo: 'useDropZone/basic', title: 'useDropZone' },
]
19 changes: 19 additions & 0 deletions docs/.vitepress/data/hookDemoSubtitles.ts
Original file line number Diff line number Diff line change
Expand Up @@ -3,6 +3,25 @@
* Keys are `useX/basic` as passed to the `demo` prop.
*/
export const hookDemoSubtitles: Record<string, string> = {
'useActiveElement/basic':
'Mirror document.activeElement and inspect focus transitions across inputs, textarea, buttons, and links.',
'useClickOutside/basic':
'Close a panel when clicks happen outside multiple protected refs (toggle button + content area).',
'useDraggable/basic':
'Drag a card by its handle and keep it inside a container while tracking position and drag state.',
'useDropZone/basic': 'Track drag-over state and capture dropped files with hover feedback and recent-drop logging.',
'useElementBounding/basic':
'Track full DOMRect values (x/y/edges/size) while a target moves inside a scrollable container.',
'useElementSize/basic':
'Observe a panel size with ResizeObserver while changing width, height, and inner padding live.',
'useElementVisibility/basic':
'Observe when a sentinel becomes visible inside a scroll root with configurable threshold.',
'useParentElement/basic':
'Resolve and inspect a target node parentElement, and interact with the parent wrapper through the returned node.',
'useWindowFocus/basic': 'Reflect current window focus/blur state and demonstrate focus-aware background ticking.',
'useWindowScroll/basic': 'Track live window scrollX/scrollY and expose quick actions for top/middle/end navigation.',
'useTextareaAutoSize/basic':
'Autosize a textarea to content height; optionally sync the measured height to a wrapper via styleTarget.',
'useToggle/basic':
'Boolean (or set) state with a flip/toggle, optional custom setters, and a stable toggler function.',
'useCounter/basic': 'Increment, decrement, or set a number with optional min/max so values stay in range.',
Expand Down
42 changes: 41 additions & 1 deletion docs/.vitepress/theme/components/HomeHookShowcase.vue
Original file line number Diff line number Diff line change
Expand Up @@ -2,6 +2,7 @@
import { computed, ref } from 'vue'
import { withBase } from 'vitepress'
import { homeStateDemos } from '../../data/homeStateDemos'
import { homeElementsDemos } from '../../data/homeElementsDemos'

/** Open card ids - several demos can stay open at once. */
const expandedDemos = ref<string[]>([])
Expand Down Expand Up @@ -158,7 +159,42 @@ function onDemoItemKeydown(demo: string, ev: KeyboardEvent) {
</div>
</section>

<!-- e.g. <section class="home-showcase__section" …> + homeBrowserDemos when ready -->
<section
class="home-showcase__section home-showcase__section--spaced"
aria-labelledby="home-showcase-elements-title"
>
<div class="home-showcase__section-head">
<h3 id="home-showcase-elements-title" class="home-showcase__section-title">Elements</h3>
</div>
<p class="home-showcase__section-lead">
DOM-focused helpers: textarea autosize, outside click handling, drag/drop, element measurement, focus and
scroll state. Browse
<a class="home-showcase__state-link" :href="withBase('/functions/elements')"
>Elements in the function list →</a
>
</p>

<div class="home-state-demos" role="list">
<article
v-for="(item, index) in homeElementsDemos"
:key="item.demo"
class="home-state-demos__item"
:class="{ 'home-state-demos__item--expanded': isCardExpanded(item.demo) }"
:style="{ '--stagger': String(index) }"
role="listitem"
tabindex="0"
:aria-expanded="isCardExpanded(item.demo)"
@click="onDemoItemClick(item.demo, $event)"
@keydown="onDemoItemKeydown(item.demo, $event)"
>
<HookLiveDemo
:demo="item.demo"
:title="item.title"
:title-href="withBase(`/functions/${item.demo.split('/')[0]}`)"
/>
</article>
</div>
</section>
</div>
</div>
</template>
Expand Down Expand Up @@ -240,6 +276,10 @@ function onDemoItemKeydown(demo: string, ev: KeyboardEvent) {
background: transparent;
}

.home-showcase__section--spaced {
margin-top: 2.2rem;
}

.home-showcase__section-head {
display: flex;
flex-wrap: wrap;
Expand Down
11 changes: 11 additions & 0 deletions docs/.vitepress/theme/components/HookLiveDemo.vue
Original file line number Diff line number Diff line change
Expand Up @@ -40,9 +40,20 @@ const activeSource = computed(() => sourceJsx.value)
const sourceOpen = ref(false)

const demoLoaders: Record<string, () => Promise<DemoModule>> = {
'useActiveElement/basic': () => import('../react-demos/useActiveElement.basic'),
'useAsyncState/basic': () => import('../react-demos/useAsyncState.basic'),
'useCounter/basic': () => import('../react-demos/useCounter.basic'),
'useClickOutside/basic': () => import('../react-demos/useClickOutside.basic'),
'useDraggable/basic': () => import('../react-demos/useDraggable.basic'),
'useElementBounding/basic': () => import('../react-demos/useElementBounding.basic'),
'useElementSize/basic': () => import('../react-demos/useElementSize.basic'),
'useElementVisibility/basic': () => import('../react-demos/useElementVisibility.basic'),
'useParentElement/basic': () => import('../react-demos/useParentElement.basic'),
'useTextareaAutoSize/basic': () => import('../react-demos/useTextareaAutoSize.basic'),
'useWindowFocus/basic': () => import('../react-demos/useWindowFocus.basic'),
'useWindowScroll/basic': () => import('../react-demos/useWindowScroll.basic'),
'useDebouncedRefHistory/basic': () => import('../react-demos/useDebouncedRefHistory.basic'),
'useDropZone/basic': () => import('../react-demos/useDropZone.basic'),
'useToggle/basic': () => import('../react-demos/useToggle.basic'),
'useDebounce/basic': () => import('../react-demos/useDebounce.basic'),
'useEventCallback/basic': () => import('../react-demos/useEventCallback.basic'),
Expand Down
160 changes: 160 additions & 0 deletions docs/.vitepress/theme/react-demos/useActiveElement.basic.ts
Original file line number Diff line number Diff line change
@@ -0,0 +1,160 @@
import React from 'react'
import useActiveElement from '@dedalik/use-react/useActiveElement'

function describeElement(el: Element | null): string {
if (!el || !(el instanceof HTMLElement)) return 'none'
const id = el.id ? `#${el.id}` : ''
const name = 'name' in el && typeof (el as HTMLInputElement).name === 'string' ? (el as HTMLInputElement).name : ''
return `${el.tagName.toLowerCase()}${id}${name ? `[name=${name}]` : ''}`
}

function ActiveElementDemo() {
const active = useActiveElement()

return React.createElement(
'div',
{ className: 'hook-demo-surface' },
React.createElement(
'p',
{ className: 'hook-demo-hint' },
'Move focus with mouse, Tab, or programmatic focus to see document.activeElement update in real time.',
),
React.createElement(
'p',
{ style: { margin: '0 0 10px' } },
'Active element: ',
React.createElement('strong', null, describeElement(active)),
),
React.createElement(
'div',
{ style: { display: 'grid', gap: 8, maxWidth: 460 } },
React.createElement(
'label',
{ htmlFor: 'ae-email', style: { display: 'grid', gap: 4 } },
React.createElement('span', null, 'Email'),
React.createElement('input', {
id: 'ae-email',
name: 'email',
type: 'email',
placeholder: 'you@example.com',
}),
),
React.createElement(
'label',
{ htmlFor: 'ae-notes', style: { display: 'grid', gap: 4 } },
React.createElement('span', null, 'Notes'),
React.createElement('textarea', {
id: 'ae-notes',
name: 'notes',
rows: 3,
placeholder: 'Type here...',
}),
),
React.createElement(
'div',
{ className: 'hook-demo-toolbar', style: { gridTemplateColumns: 'repeat(3, minmax(0, 1fr))' } },
React.createElement(
'button',
{
type: 'button',
onClick: () => {
const el = document.getElementById('ae-email') as HTMLInputElement | null
el?.focus()
},
},
'Focus email',
),
React.createElement(
'button',
{
type: 'button',
onClick: () => {
const el = document.getElementById('ae-notes') as HTMLTextAreaElement | null
el?.focus()
},
},
'Focus notes',
),
React.createElement(
'button',
{
type: 'button',
onClick: () => {
const activeEl = document.activeElement as HTMLElement | null
activeEl?.blur()
},
},
'Blur active',
),
),
),
)
}

export const sourceJsx = `import useActiveElement from '@dedalik/use-react/useActiveElement'

function describeElement(el: Element | null): string {
if (!el || !(el instanceof HTMLElement)) return 'none'
const id = el.id ? '#' + el.id : ''
const name = 'name' in el && typeof (el as HTMLInputElement).name === 'string' ? (el as HTMLInputElement).name : ''
return el.tagName.toLowerCase() + id + (name ? '[name=' + name + ']' : '')
}

export default function ActiveElementDemo() {
const active = useActiveElement()

return (
<div className='hook-demo-surface'>
<p className='hook-demo-hint'>
Move focus with mouse, Tab, or programmatic focus to see document.activeElement update in real time.
</p>
<p style={{ margin: '0 0 10px' }}>
Active element: <strong>{describeElement(active)}</strong>
</p>

<div style={{ display: 'grid', gap: 8, maxWidth: 460 }}>
<label htmlFor='ae-email' style={{ display: 'grid', gap: 4 }}>
<span>Email</span>
<input id='ae-email' name='email' type='email' placeholder='you@example.com' />
</label>
<label htmlFor='ae-notes' style={{ display: 'grid', gap: 4 }}>
<span>Notes</span>
<textarea id='ae-notes' name='notes' rows={3} placeholder='Type here...' />
</label>

<div className='hook-demo-toolbar' style={{ gridTemplateColumns: 'repeat(3, minmax(0, 1fr))' }}>
<button
type='button'
onClick={() => {
const el = document.getElementById('ae-email') as HTMLInputElement | null
el?.focus()
}}
>
Focus email
</button>
<button
type='button'
onClick={() => {
const el = document.getElementById('ae-notes') as HTMLTextAreaElement | null
el?.focus()
}}
>
Focus notes
</button>
<button
type='button'
onClick={() => {
const activeEl = document.activeElement as HTMLElement | null
activeEl?.blur()
}}
>
Blur active
</button>
</div>

</div>
</div>
)
}`

export default ActiveElementDemo
Loading