Files
zeekayandHanzo Dev 751ef5c778 rename the framework to @hanzo/gui and the loader to @hanzogui/loader
Both old names are owned by a different npm account (artemis-prime), so
publishing them returns 403 — which is how this surfaced: the 8.0.0 run
shipped @hanzogui/logo and @hanzogui/demos depending on [email protected], a
version that cannot be published and therefore does not exist. Those two
were uninstallable.

@hanzo/gui and @hanzogui/* are ours, so the framework now carries the name
it is imported by everywhere downstream, and the loader moves under the
scope we control.

The rewrite is limited to package references. `DEBUG?.startsWith('hanzogui')`
is a log-namespace filter and join(dir, 'hanzogui') is a path — rewriting
either would change behaviour, so both are untouched.

Co-authored-by: Hanzo Dev <[email protected]>
2026-07-30 20:23:18 -07:00

192 lines
6.2 KiB
TypeScript

import {
Backpack,
Calendar,
Check,
ChevronRight,
FilePlus,
Trash2,
RefreshCw,
} from '@hanzogui/lucide-icons-2'
import { Menu } from '@hanzogui/menu'
import React from 'react'
import { Button, View } from '@hanzo/gui'
import { isTouchable } from '@hanzogui/constants'
/**
* Menu Demo using Gui Menu component.
* Automatically uses native menus on iOS/Android, web menus on web.
* No configuration needed - it just works!
*/
/**
* Note: you'll want to use createMenu() to customize further.
*/
export function MenuDemo() {
const [bookmarksChecked, setBookmarksChecked] = React.useState(true)
const [native, setNative] = React.useState(true)
const [subMenuOpen, setSubMenuOpen] = React.useState(false)
// Note: `item` is the Event on web, undefined on native
const onSelect = (item) => {
console.info(`selected`, item)
}
console.log('isTouchable: ', isTouchable)
return (
<>
<Menu
offset={{
crossAxis: 25,
}}
allowFlip
placement="bottom-start"
>
<Menu.Trigger asChild>
<Button size="$3" circular icon={Backpack} scaleIcon={1.2} marginLeft="$20" />
</Menu.Trigger>
<Menu.Portal zIndex={100}>
<Menu.Content
paddingHorizontal={0}
borderWidth={1}
items="flex-start"
borderColor="$borderColor"
backgroundColor="$color1"
enterStyle={{ scale: 0.4, opacity: 0, y: -10 }}
exitStyle={{ scale: 0.6, opacity: 0, y: -5 }}
animation="menu"
transformOrigin="top"
>
<Menu.Item onSelect={onSelect} key="about-notes">
<Menu.ItemTitle>About Notes</Menu.ItemTitle>
</Menu.Item>
<Menu.Separator />
<Menu.Group>
<Menu.Item onSelect={onSelect} key="settings">
<Menu.ItemTitle>Settings</Menu.ItemTitle>
</Menu.Item>
<Menu.Item
onSelect={onSelect}
key="accounts"
justify="space-between"
// when title is nested inside a React element then you need to use `textValue`
textValue="Calendar"
>
<Menu.ItemTitle>Calendar</Menu.ItemTitle>
<Menu.ItemIcon
androidIconName="ic_menu_today"
ios={{
name: 'calendar',
hierarchicalColor: '#000',
pointSize: 20,
}}
>
<Calendar color="gray" size={14} />
</Menu.ItemIcon>
</Menu.Item>
</Menu.Group>
<Menu.Separator />
<Menu.Group>
<Menu.Item onSelect={onSelect} key="close-notes" disabled>
<Menu.ItemTitle color="gray">Locked Notes</Menu.ItemTitle>
</Menu.Item>
<Menu.Item onSelect={onSelect} destructive key="delete-all">
<Menu.ItemTitle color="red">Delete all</Menu.ItemTitle>
</Menu.Item>
</Menu.Group>
<Menu.Separator />
{/* Submenu - placement auto-adapts based on Menu.Adapt */}
<Menu.Sub open={subMenuOpen} onOpenChange={setSubMenuOpen}>
<Menu.SubTrigger
justify="space-between"
key="actions-trigger"
textValue="Actions"
>
<>
<Menu.ItemTitle>Actions</Menu.ItemTitle>
<View rotate={subMenuOpen ? '90deg' : '0deg'} animation="quicker">
<ChevronRight size="$1" />
</View>
</>
</Menu.SubTrigger>
<Menu.Portal zIndex={200}>
<Menu.SubContent
enterStyle={{ scale: 0.5, opacity: 0, y: -5 }}
exitStyle={{ scale: 0.7, opacity: 0, y: -3 }}
animation="menu"
transformOrigin="top left"
elevation="$5"
scale={1.02}
backgroundColor="$color1"
>
<Menu.Item
onSelect={onSelect}
key="create-note"
textValue="Create note"
>
<Menu.ItemTitle>Create note</Menu.ItemTitle>
<Menu.ItemIcon>
<FilePlus size={18} color="$color10" />
</Menu.ItemIcon>
</Menu.Item>
<Menu.Item
onSelect={onSelect}
key="delete-all"
textValue="Delete all notes"
>
<Menu.ItemTitle>Delete all notes</Menu.ItemTitle>
<Menu.ItemIcon>
<Trash2 size={18} color="$color10" />
</Menu.ItemIcon>
</Menu.Item>
<Menu.Item onSelect={onSelect} key="sync-all" textValue="Sync notes">
<Menu.ItemTitle>Sync notes</Menu.ItemTitle>
<Menu.ItemIcon>
<RefreshCw size={18} color="$color10" />
</Menu.ItemIcon>
</Menu.Item>
</Menu.SubContent>
</Menu.Portal>
</Menu.Sub>
<Menu.Separator />
<Menu.CheckboxItem
key="show-hidden"
checked={bookmarksChecked}
onCheckedChange={setBookmarksChecked}
gap={'$2'}
>
<Menu.ItemTitle>Mark as read</Menu.ItemTitle>
<Menu.ItemIndicator>
<Check size={16} color="$color10" />
</Menu.ItemIndicator>
</Menu.CheckboxItem>
<Menu.CheckboxItem
key="show-other-notes"
checked={native}
onCheckedChange={setNative}
gap={'$2'}
>
<Menu.ItemTitle>Enable Native</Menu.ItemTitle>
<Menu.ItemIndicator>
<Check size={16} color="$color10" />
</Menu.ItemIndicator>
</Menu.CheckboxItem>
<Menu.Arrow size={'$2'} />
</Menu.Content>
</Menu.Portal>
</Menu>
</>
)
}