mirror of
https://github.com/hanzoai/gui.git
synced 2026-10-25 02:31:41 +00:00
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]>
192 lines
6.2 KiB
TypeScript
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>
|
|
</>
|
|
)
|
|
}
|