@hamster-note/components 0.2.0
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- package/LICENSE +21 -0
- package/README.md +411 -0
- package/dist/badge-BxBwSGqN.js +16 -0
- package/dist/badge.d.ts +2 -0
- package/dist/badge.js +2 -0
- package/dist/button-DRz0VTkf.js +18 -0
- package/dist/button.d.ts +2 -0
- package/dist/button.js +2 -0
- package/dist/components/badge/Badge.d.ts +7 -0
- package/dist/components/badge/index.d.ts +2 -0
- package/dist/components/button/Button.d.ts +9 -0
- package/dist/components/button/index.d.ts +2 -0
- package/dist/components/confirm/Confirm.d.ts +24 -0
- package/dist/components/confirm/confirm.d.ts +3 -0
- package/dist/components/confirm/index.d.ts +3 -0
- package/dist/components/dialog/Dialog.d.ts +11 -0
- package/dist/components/dialog/index.d.ts +2 -0
- package/dist/components/dialog/use-modal.d.ts +22 -0
- package/dist/components/drawer/Drawer.d.ts +14 -0
- package/dist/components/drawer/index.d.ts +2 -0
- package/dist/components/icon/Icon.d.ts +28 -0
- package/dist/components/icon/icon-names.d.ts +15 -0
- package/dist/components/icon/index.d.ts +4 -0
- package/dist/components/kbd/Kbd.d.ts +6 -0
- package/dist/components/kbd/index.d.ts +2 -0
- package/dist/components/loading/Loading.d.ts +12 -0
- package/dist/components/loading/index.d.ts +3 -0
- package/dist/components/loading/loading.d.ts +3 -0
- package/dist/components/menu/Menu.d.ts +25 -0
- package/dist/components/menu/index.d.ts +2 -0
- package/dist/components/note-card/NoteCard.d.ts +9 -0
- package/dist/components/note-card/index.d.ts +2 -0
- package/dist/components/popover/Popover.d.ts +21 -0
- package/dist/components/popover/index.d.ts +2 -0
- package/dist/components/popover/use-anchor-position.d.ts +14 -0
- package/dist/components/text-field/TextField.d.ts +7 -0
- package/dist/components/text-field/index.d.ts +2 -0
- package/dist/components/theme/ThemeProvider.d.ts +77 -0
- package/dist/components/theme/index.d.ts +4 -0
- package/dist/components/theme/theme.d.ts +87 -0
- package/dist/confirm-3eBmopl8.js +109 -0
- package/dist/confirm.d.ts +2 -0
- package/dist/confirm.js +2 -0
- package/dist/dialog-B4xS5zlK.js +53 -0
- package/dist/dialog.d.ts +2 -0
- package/dist/dialog.js +2 -0
- package/dist/drawer-DoeuGAHD.js +60 -0
- package/dist/drawer.d.ts +2 -0
- package/dist/drawer.js +2 -0
- package/dist/hamster-note-components.css +2 -0
- package/dist/icon-C40ONpMt.js +451 -0
- package/dist/icon.d.ts +2 -0
- package/dist/icon.js +2 -0
- package/dist/index.d.ts +26 -0
- package/dist/index.js +14 -0
- package/dist/kbd-D9XXd3qf.js +39 -0
- package/dist/kbd.d.ts +2 -0
- package/dist/kbd.js +2 -0
- package/dist/loading-BpykjzMR.js +88 -0
- package/dist/loading.d.ts +2 -0
- package/dist/loading.js +2 -0
- package/dist/menu-B6uuZFif.js +142 -0
- package/dist/menu.d.ts +2 -0
- package/dist/menu.js +2 -0
- package/dist/note-card-Dm-WbNTO.js +50 -0
- package/dist/note-card.d.ts +2 -0
- package/dist/note-card.js +2 -0
- package/dist/popover-Qg_fA2A_.js +165 -0
- package/dist/popover.d.ts +2 -0
- package/dist/popover.js +2 -0
- package/dist/text-field-B8Scu04G.js +31 -0
- package/dist/text-field.d.ts +2 -0
- package/dist/text-field.js +2 -0
- package/dist/theme-C0p_hpKk.js +67 -0
- package/dist/theme.d.ts +2 -0
- package/dist/theme.js +2 -0
- package/dist/use-modal-K9L8aPS0.js +82 -0
- package/package.json +111 -0
|
@@ -0,0 +1,6 @@
|
|
|
1
|
+
import { HTMLAttributes, ReactNode } from 'react';
|
|
2
|
+
export interface KbdProps extends HTMLAttributes<HTMLElement> {
|
|
3
|
+
readonly children?: ReactNode;
|
|
4
|
+
readonly keys?: readonly string[];
|
|
5
|
+
}
|
|
6
|
+
export declare function Kbd({ children, className, keys, ...props }: KbdProps): import("react").JSX.Element;
|
|
@@ -0,0 +1,12 @@
|
|
|
1
|
+
import { HTMLAttributes } from 'react';
|
|
2
|
+
export type LoadingSize = 'small' | 'medium' | 'large';
|
|
3
|
+
export interface LoadingOptions {
|
|
4
|
+
readonly text?: string | undefined;
|
|
5
|
+
readonly size?: LoadingSize | undefined;
|
|
6
|
+
}
|
|
7
|
+
export interface LoadingProps extends HTMLAttributes<HTMLDivElement> {
|
|
8
|
+
readonly size?: LoadingSize | undefined;
|
|
9
|
+
readonly text?: string | undefined;
|
|
10
|
+
readonly cover?: boolean | undefined;
|
|
11
|
+
}
|
|
12
|
+
export declare function Loading({ size, text, cover, className, children, ...props }: LoadingProps): import("react").JSX.Element;
|
|
@@ -0,0 +1,25 @@
|
|
|
1
|
+
import { ButtonHTMLAttributes, HTMLAttributes, ReactNode } from 'react';
|
|
2
|
+
export type MenuItemTone = 'default' | 'danger';
|
|
3
|
+
export interface MenuProps extends HTMLAttributes<HTMLDivElement> {
|
|
4
|
+
readonly children: ReactNode;
|
|
5
|
+
}
|
|
6
|
+
export interface MenuItemProps extends ButtonHTMLAttributes<HTMLButtonElement> {
|
|
7
|
+
readonly children: ReactNode;
|
|
8
|
+
readonly tone?: MenuItemTone;
|
|
9
|
+
readonly shortcut?: ReactNode;
|
|
10
|
+
}
|
|
11
|
+
export type MenuSeparatorProps = Omit<HTMLAttributes<HTMLHRElement>, 'children'>;
|
|
12
|
+
export interface MenuLabelProps extends HTMLAttributes<HTMLDivElement> {
|
|
13
|
+
readonly children: ReactNode;
|
|
14
|
+
}
|
|
15
|
+
export interface MenuSubmenuProps extends Omit<HTMLAttributes<HTMLDivElement>, 'children'> {
|
|
16
|
+
readonly label: ReactNode;
|
|
17
|
+
readonly children: ReactNode;
|
|
18
|
+
readonly 'aria-label'?: string;
|
|
19
|
+
readonly disabled?: boolean;
|
|
20
|
+
}
|
|
21
|
+
export declare function Menu({ children, className, ...props }: MenuProps): import("react").JSX.Element;
|
|
22
|
+
export declare function MenuItem({ children, className, shortcut, tone, type, ...props }: MenuItemProps): import("react").JSX.Element;
|
|
23
|
+
export declare function MenuSeparator({ className, ...props }: MenuSeparatorProps): import("react").JSX.Element;
|
|
24
|
+
export declare function MenuLabel({ children, className, ...props }: MenuLabelProps): import("react").JSX.Element;
|
|
25
|
+
export declare function MenuSubmenu({ label, children, className, disabled, 'aria-label': ariaLabel, ...props }: MenuSubmenuProps): import("react").JSX.Element;
|
|
@@ -0,0 +1,9 @@
|
|
|
1
|
+
import { HTMLAttributes, MouseEventHandler } from 'react';
|
|
2
|
+
export interface NoteCardProps extends Omit<HTMLAttributes<HTMLElement>, 'onClick' | 'title'> {
|
|
3
|
+
readonly excerpt: string;
|
|
4
|
+
readonly meta: string;
|
|
5
|
+
readonly onClick?: MouseEventHandler<HTMLButtonElement>;
|
|
6
|
+
readonly selected?: boolean;
|
|
7
|
+
readonly title: string;
|
|
8
|
+
}
|
|
9
|
+
export declare function NoteCard({ className, excerpt, meta, onClick, selected, title, ...props }: NoteCardProps): import("react").JSX.Element;
|
|
@@ -0,0 +1,21 @@
|
|
|
1
|
+
import { HTMLAttributes, ReactNode, Ref } from 'react';
|
|
2
|
+
import { FloatingPlacement } from './use-anchor-position';
|
|
3
|
+
export type PopoverTheme = 'dark' | 'light';
|
|
4
|
+
export type PopoverOrientation = 'horizontal' | 'vertical';
|
|
5
|
+
export type PopoverEdge = 'top' | 'bottom' | 'left' | 'right';
|
|
6
|
+
export type PopoverPlacement = FloatingPlacement;
|
|
7
|
+
export interface PopoverProps extends HTMLAttributes<HTMLDivElement> {
|
|
8
|
+
readonly children: ReactNode;
|
|
9
|
+
readonly theme?: PopoverTheme;
|
|
10
|
+
readonly orientation?: PopoverOrientation;
|
|
11
|
+
readonly edge?: PopoverEdge;
|
|
12
|
+
readonly edgeOffset?: number;
|
|
13
|
+
readonly anchor?: HTMLElement | null;
|
|
14
|
+
readonly placement?: PopoverPlacement;
|
|
15
|
+
readonly anchorOffset?: number;
|
|
16
|
+
readonly viewportMargin?: number;
|
|
17
|
+
readonly ref?: Ref<HTMLDivElement>;
|
|
18
|
+
}
|
|
19
|
+
export type PopoverSeparatorProps = Omit<HTMLAttributes<HTMLHRElement>, 'aria-orientation' | 'children' | 'role'>;
|
|
20
|
+
export declare function Popover({ children, className, theme, orientation, edge, edgeOffset, anchor, placement, anchorOffset, viewportMargin, ref, style, ...props }: PopoverProps): import("react").JSX.Element;
|
|
21
|
+
export declare function PopoverSeparator({ className, ...props }: PopoverSeparatorProps): import("react").JSX.Element;
|
|
@@ -0,0 +1,14 @@
|
|
|
1
|
+
import { CSSProperties, RefObject } from 'react';
|
|
2
|
+
export type FloatingPlacement = 'top-start' | 'top-end' | 'bottom-start' | 'bottom-end' | 'left-start' | 'right-start';
|
|
3
|
+
export interface UseAnchorPositionOptions {
|
|
4
|
+
readonly anchor: HTMLElement | null;
|
|
5
|
+
readonly placement?: FloatingPlacement;
|
|
6
|
+
readonly offset?: number;
|
|
7
|
+
readonly crossOffset?: number;
|
|
8
|
+
readonly viewportMargin?: number;
|
|
9
|
+
}
|
|
10
|
+
export interface UseAnchorPositionResult {
|
|
11
|
+
readonly floatingRef: RefObject<HTMLDivElement | null>;
|
|
12
|
+
readonly style: CSSProperties;
|
|
13
|
+
}
|
|
14
|
+
export declare function useAnchorPosition({ anchor, placement, offset, crossOffset, viewportMargin, }: UseAnchorPositionOptions): UseAnchorPositionResult;
|
|
@@ -0,0 +1,7 @@
|
|
|
1
|
+
import { InputHTMLAttributes } from 'react';
|
|
2
|
+
export interface TextFieldProps extends Omit<InputHTMLAttributes<HTMLInputElement>, 'size'> {
|
|
3
|
+
readonly error?: string;
|
|
4
|
+
readonly hint?: string;
|
|
5
|
+
readonly label: string;
|
|
6
|
+
}
|
|
7
|
+
export declare function TextField({ 'aria-describedby': ariaDescribedBy, error, hint, id, label, ...props }: TextFieldProps): import("react").JSX.Element;
|
|
@@ -0,0 +1,77 @@
|
|
|
1
|
+
import { CSSProperties, ReactNode } from 'react';
|
|
2
|
+
import { ThemeAccent, ThemeMode } from './theme';
|
|
3
|
+
/**
|
|
4
|
+
* ThemeProvider 的 props。
|
|
5
|
+
*/
|
|
6
|
+
export interface ThemeProviderProps {
|
|
7
|
+
/**
|
|
8
|
+
* 主题色 accent。两种来源:
|
|
9
|
+
* - 预设名(`violet` / `blue` / `teal` / `orange` / `pink`):从
|
|
10
|
+
* THEME_ACCENTS 读取精确的 accent / accentHover / focusRing 三件套
|
|
11
|
+
* 内联下发,保证与 TS 配置完全一致;
|
|
12
|
+
* - 任意 CSS 颜色字符串(如 `#ff8a3d` / `oklch(...)`):只下发
|
|
13
|
+
* `--hn-color-accent`,hover 与 focusRing 由 theme.css 的
|
|
14
|
+
* `[data-accent='custom']` 规则用 color-mix 实时派生。
|
|
15
|
+
*
|
|
16
|
+
* 默认 `violet`,与 tokens.css 的默认值一致,不传时视觉无变化。
|
|
17
|
+
*
|
|
18
|
+
* 与 `mode` 正交:accent 影响 `--hn-color-accent` 三件套,mode 影响全套
|
|
19
|
+
* 表面/文字/边框 token,两个轴独立组合。
|
|
20
|
+
*/
|
|
21
|
+
readonly accent?: ThemeAccent;
|
|
22
|
+
readonly children: ReactNode;
|
|
23
|
+
/** 追加到根 div 的 className,便于使用方做布局或测试钩子。 */
|
|
24
|
+
readonly className?: string;
|
|
25
|
+
/**
|
|
26
|
+
* 明暗模式:`'dark'`(默认)或 `'light'`。
|
|
27
|
+
*
|
|
28
|
+
* 始终写入根 div 的 `data-mode` 属性(即便用默认值),让 theme.css 的
|
|
29
|
+
* `.hn-theme[data-mode='dark']` / `.hn-theme[data-mode='light']` 规则都能
|
|
30
|
+
* 命中,保证嵌套场景下内层 Provider 的 mode 可以预测地覆盖外层(例如
|
|
31
|
+
* light 内嵌套 dark 时,内层显式 data-mode='dark' 会强制把 token 拉回深色)。
|
|
32
|
+
*
|
|
33
|
+
* 与 `accent` 正交:mode 重定义 `--hn-color-surface` / `--hn-color-text` /
|
|
34
|
+
* `--hn-color-border` 等全套表面与文字 token,accent 只影响 accent 三件套。
|
|
35
|
+
* 两个轴在同一包裹层上共存(`data-mode` + `data-accent` + 内联 accent style)。
|
|
36
|
+
*
|
|
37
|
+
* 实际 token 覆盖值定义在 theme.css 中,ThemeProvider 只负责把 mode 透传到
|
|
38
|
+
* `data-mode` 属性,CSS 级联完成其余工作。
|
|
39
|
+
*/
|
|
40
|
+
readonly mode?: ThemeMode;
|
|
41
|
+
/** 追加到根 div 的 style,合并时排在 ThemeProvider 内联 style 之后,可覆盖主题变量。 */
|
|
42
|
+
readonly style?: CSSProperties;
|
|
43
|
+
}
|
|
44
|
+
/**
|
|
45
|
+
* 主题 Provider:包裹子树即可切换 accent 主色与明暗模式。
|
|
46
|
+
*
|
|
47
|
+
* 实现:渲染一个 `<div class="hn-theme" data-accent="..." data-mode="..." style="...">`
|
|
48
|
+
* 包裹层,在内联 style 上重定义 `--hn-color-accent` / `--hn-color-accent-hover` /
|
|
49
|
+
* `--hn-focus-ring` 三个 accent token,同时通过 `data-mode` 属性让 theme.css 的
|
|
50
|
+
* `.hn-theme[data-mode='dark']` / `.hn-theme[data-mode='light']` 规则重定义全套
|
|
51
|
+
* 表面与文字 token(surface/text/border 等)。由于 CSS 自定义属性天然经级联
|
|
52
|
+
* 继承,子树所有组件无需任何改动即可吃到新主题 -- 这是本库「组件只引用全局
|
|
53
|
+
* token、主题靠包裹层覆盖 token」哲学的直接应用(与 Popover 的 dark/light
|
|
54
|
+
* 同范式)。
|
|
55
|
+
*
|
|
56
|
+
* 两个正交轴:
|
|
57
|
+
* - accent(主色):影响 Button primary、TextField 焦点边框、NoteCard/Menu/
|
|
58
|
+
* Dialog/Drawer 焦点环、Loading 颜色等 accent 相关组件;
|
|
59
|
+
* - mode(明暗):影响所有引用 surface/text/border token 的组件的背景与文字。
|
|
60
|
+
* 两个轴独立组合,例如 `<ThemeProvider mode="light" accent="blue">`。
|
|
61
|
+
*
|
|
62
|
+
* `.hn-theme` 用 `display: contents` 让包裹 div 在盒模型上消失,不额外产生
|
|
63
|
+
* 一层盒子、不打断外层 flex/grid 布局,因此不要在它上面设置背景/圆角等视觉样式
|
|
64
|
+
* -- 页面级的 `background: var(--hn-color-surface)` 应由使用方在 app 根上应用。
|
|
65
|
+
*
|
|
66
|
+
* 支持嵌套:内层 ThemeProvider 经级联自然覆盖外层,最内层的 accent 与 mode 同时生效。
|
|
67
|
+
* 例如:
|
|
68
|
+
* ```tsx
|
|
69
|
+
* <ThemeProvider mode="light" accent="blue">
|
|
70
|
+
* <ThemeProvider mode="dark" accent="teal">
|
|
71
|
+
* <Button variant="primary">我是 teal + 深色背景</Button>
|
|
72
|
+
* </ThemeProvider>
|
|
73
|
+
* <Button variant="primary">我是 blue + 浅色背景</Button>
|
|
74
|
+
* </ThemeProvider>
|
|
75
|
+
* ```
|
|
76
|
+
*/
|
|
77
|
+
export declare function ThemeProvider({ accent, children, className, mode, style, }: ThemeProviderProps): import("react").JSX.Element;
|
|
@@ -0,0 +1,87 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* 主题色配置(accent 主色)。
|
|
3
|
+
*
|
|
4
|
+
* 设计哲学:组件库所有组件只引用全局 token(见 tokens.css 的 :root),
|
|
5
|
+
* 主题切换通过在包裹层重定义同名 token、经 CSS 级联让子树自动继承
|
|
6
|
+
* (Popover 的 dark/light 即是这一范式)。本文件是 accent 主题色的
|
|
7
|
+
* 唯一数据源:ThemeProvider 读取这里的预设值,内联下发到包裹 div 的
|
|
8
|
+
* style 上,子树所有组件经 var(--hn-color-accent) 等拿到新色值。
|
|
9
|
+
*
|
|
10
|
+
* 预设色刻意避开既有语义色(danger #fb7185 / success #4ade80 /
|
|
11
|
+
* warning #fbbf24),避免主题色与语义色产生视觉冲突。
|
|
12
|
+
*/
|
|
13
|
+
/**
|
|
14
|
+
* 预设主题色表。
|
|
15
|
+
*
|
|
16
|
+
* 每个预设包含三个字段,分别对应 tokens.css 中被 accent 影响的三个 token:
|
|
17
|
+
* - accent:主色,映射到 --hn-color-accent
|
|
18
|
+
* - accentHover:hover 态色,映射到 --hn-color-accent-hover
|
|
19
|
+
* - focusRingColor:焦点环颜色(不含 box-shadow 前缀,仅颜色部分),
|
|
20
|
+
* ThemeProvider 会拼成 `0 0 0 3px ${focusRingColor}` 写入 --hn-focus-ring
|
|
21
|
+
*
|
|
22
|
+
* `violet` 与 tokens.css 的默认值完全一致,作为 ThemeProvider 的默认预设,
|
|
23
|
+
* 保证不传 accent 时视觉与未包裹 ThemeProvider 时完全等价(零 Breaking Change)。
|
|
24
|
+
*/
|
|
25
|
+
export declare const THEME_ACCENTS: {
|
|
26
|
+
readonly violet: {
|
|
27
|
+
readonly accent: "#7c83ff";
|
|
28
|
+
readonly accentHover: "#9197ff";
|
|
29
|
+
readonly focusRingColor: "rgb(145 151 255 / 42%)";
|
|
30
|
+
};
|
|
31
|
+
readonly blue: {
|
|
32
|
+
readonly accent: "#60a5fa";
|
|
33
|
+
readonly accentHover: "#7db6fb";
|
|
34
|
+
readonly focusRingColor: "rgb(96 165 250 / 42%)";
|
|
35
|
+
};
|
|
36
|
+
readonly teal: {
|
|
37
|
+
readonly accent: "#2dd4bf";
|
|
38
|
+
readonly accentHover: "#4fdcc9";
|
|
39
|
+
readonly focusRingColor: "rgb(45 212 191 / 42%)";
|
|
40
|
+
};
|
|
41
|
+
readonly orange: {
|
|
42
|
+
readonly accent: "#fb923c";
|
|
43
|
+
readonly accentHover: "#fca45c";
|
|
44
|
+
readonly focusRingColor: "rgb(251 146 60 / 42%)";
|
|
45
|
+
};
|
|
46
|
+
readonly pink: {
|
|
47
|
+
readonly accent: "#f472b6";
|
|
48
|
+
readonly accentHover: "#f68cc4";
|
|
49
|
+
readonly focusRingColor: "rgb(244 114 182 / 42%)";
|
|
50
|
+
};
|
|
51
|
+
};
|
|
52
|
+
/**
|
|
53
|
+
* 预设主题色名:`violet` | `blue` | `teal` | `orange` | `pink`。
|
|
54
|
+
*/
|
|
55
|
+
export type ThemeAccentPreset = keyof typeof THEME_ACCENTS;
|
|
56
|
+
/**
|
|
57
|
+
* 主题色入参类型。
|
|
58
|
+
*
|
|
59
|
+
* 用 `ThemeAccentPreset | (string & {})` 的交叉技巧保留两个能力:
|
|
60
|
+
* 1. 传入预设名时获得自动补全(IDE 列出五个预设);
|
|
61
|
+
* 2. 传入任意 CSS 颜色字符串时仍类型合法(`(string & {})` 让 TS 不会
|
|
62
|
+
* 把 string 收窄成字面量联合,避免「自定义颜色」用法被类型拒绝)。
|
|
63
|
+
*/
|
|
64
|
+
export type ThemeAccent = ThemeAccentPreset | (string & {});
|
|
65
|
+
/**
|
|
66
|
+
* 判断字符串是否是预设主题色名。
|
|
67
|
+
*
|
|
68
|
+
* 用于 Demo 或使用方在拿到一个 accent 字符串时区分「预设」与「自定义」
|
|
69
|
+
* 两种来源:预设走 ThemeProvider 内联下发的精确派生值,自定义走
|
|
70
|
+
* theme.css 中 `[data-accent='custom']` 的 color-mix 派生。
|
|
71
|
+
*/
|
|
72
|
+
export declare function isThemeAccentPreset(value: string): value is ThemeAccentPreset;
|
|
73
|
+
/**
|
|
74
|
+
* 明暗模式。
|
|
75
|
+
*
|
|
76
|
+
* 与 accent 主题色正交:accent 重定义 `--hn-color-accent` 等 accent 三件套,
|
|
77
|
+
* mode 重定义 `--hn-color-surface` / `--hn-color-text` / `--hn-color-border`
|
|
78
|
+
* 等全套表面与文字 token。两个轴独立组合,例如可以同时「浅色背景 + 蓝色 accent」。
|
|
79
|
+
*
|
|
80
|
+
* - `dark`(默认):与 tokens.css 的 :root 默认值一致,不传时视觉无变化;
|
|
81
|
+
* - `light`:重定义全套表面/文字/边框 token 为浅色配色。
|
|
82
|
+
*
|
|
83
|
+
* 实际的 token 覆盖值定义在 theme.css 的 `.hn-theme[data-mode='light']` 与
|
|
84
|
+
* `.hn-theme[data-mode='dark']` 规则中,ThemeProvider 只负责把 mode 写到
|
|
85
|
+
* 根 div 的 `data-mode` 属性上,CSS 级联完成其余工作。
|
|
86
|
+
*/
|
|
87
|
+
export type ThemeMode = 'dark' | 'light';
|
|
@@ -0,0 +1,109 @@
|
|
|
1
|
+
/* empty css */
|
|
2
|
+
import { t as e } from "./button-DRz0VTkf.js";
|
|
3
|
+
import { t } from "./dialog-B4xS5zlK.js";
|
|
4
|
+
import { jsx as n, jsxs as r } from "react/jsx-runtime";
|
|
5
|
+
import { createContext as i, createElement as a, useCallback as o, useContext as s, useMemo as c, useState as l } from "react";
|
|
6
|
+
import { createRoot as u } from "react-dom/client";
|
|
7
|
+
//#region src/components/confirm/Confirm.tsx
|
|
8
|
+
var d = i(null);
|
|
9
|
+
function f({ open: i, title: a, description: o, confirmText: s = "确认", cancelText: c = "取消", tone: l = "default", loading: u = !1, onConfirm: d, onCancel: f, closeOnEsc: p = !0, closeOnBackdrop: m = !0 }) {
|
|
10
|
+
let h = () => {
|
|
11
|
+
f();
|
|
12
|
+
};
|
|
13
|
+
return /* @__PURE__ */ n(t, {
|
|
14
|
+
closeOnBackdrop: m,
|
|
15
|
+
closeOnEsc: p,
|
|
16
|
+
description: o,
|
|
17
|
+
onClose: h,
|
|
18
|
+
open: i,
|
|
19
|
+
title: a,
|
|
20
|
+
children: /* @__PURE__ */ r("div", {
|
|
21
|
+
className: "hn-confirm__footer",
|
|
22
|
+
"data-tone": l,
|
|
23
|
+
children: [/* @__PURE__ */ n(e, {
|
|
24
|
+
disabled: u,
|
|
25
|
+
onClick: h,
|
|
26
|
+
type: "button",
|
|
27
|
+
variant: "ghost",
|
|
28
|
+
children: c
|
|
29
|
+
}), /* @__PURE__ */ n(e, {
|
|
30
|
+
disabled: u,
|
|
31
|
+
onClick: () => {
|
|
32
|
+
d();
|
|
33
|
+
},
|
|
34
|
+
type: "button",
|
|
35
|
+
variant: "primary",
|
|
36
|
+
children: u ? "处理中…" : s
|
|
37
|
+
})]
|
|
38
|
+
})
|
|
39
|
+
});
|
|
40
|
+
}
|
|
41
|
+
function p({ children: e }) {
|
|
42
|
+
let [t, i] = l(null), a = o((e) => new Promise((t) => {
|
|
43
|
+
i((n) => (n !== null && n.resolve(!1), {
|
|
44
|
+
options: e,
|
|
45
|
+
resolve: t
|
|
46
|
+
}));
|
|
47
|
+
}), []), s = () => {
|
|
48
|
+
i((e) => (e !== null && e.resolve(!0), null));
|
|
49
|
+
}, u = () => {
|
|
50
|
+
i((e) => (e !== null && e.resolve(!1), null));
|
|
51
|
+
}, p = c(() => ({ confirm: a }), [a]);
|
|
52
|
+
return /* @__PURE__ */ r(d.Provider, {
|
|
53
|
+
value: p,
|
|
54
|
+
children: [e, t === null ? null : /* @__PURE__ */ n(f, {
|
|
55
|
+
closeOnBackdrop: t.options.closeOnBackdrop,
|
|
56
|
+
closeOnEsc: t.options.closeOnEsc,
|
|
57
|
+
confirmText: t.options.confirmText,
|
|
58
|
+
cancelText: t.options.cancelText,
|
|
59
|
+
description: t.options.description,
|
|
60
|
+
loading: t.options.loading,
|
|
61
|
+
onConfirm: s,
|
|
62
|
+
onCancel: u,
|
|
63
|
+
open: !0,
|
|
64
|
+
title: t.options.title,
|
|
65
|
+
tone: t.options.tone
|
|
66
|
+
})]
|
|
67
|
+
});
|
|
68
|
+
}
|
|
69
|
+
function m() {
|
|
70
|
+
let e = s(d);
|
|
71
|
+
if (e === null) throw Error("useConfirm 必须在 <ConfirmProvider> 内部调用;在组件树顶层包裹 ConfirmProvider 后再使用。");
|
|
72
|
+
return e.confirm;
|
|
73
|
+
}
|
|
74
|
+
//#endregion
|
|
75
|
+
//#region src/components/confirm/confirm.ts
|
|
76
|
+
function h(e) {
|
|
77
|
+
if (typeof document > "u") return console.warn("[hamster-note/components] confirm() 在非浏览器环境(无 document)下被调用,已直接 resolve(false)。请在客户端副作用中调用,或改用 <Confirm> 组件 / useConfirm() hook。"), Promise.resolve(!1);
|
|
78
|
+
let t = document.createElement("div");
|
|
79
|
+
document.body.appendChild(t);
|
|
80
|
+
let n = u(t), r = () => {
|
|
81
|
+
n.unmount(), Promise.resolve().then(() => {
|
|
82
|
+
t.parentNode !== null && t.parentNode.removeChild(t);
|
|
83
|
+
});
|
|
84
|
+
};
|
|
85
|
+
return new Promise((t) => {
|
|
86
|
+
let i = (e) => {
|
|
87
|
+
t(e), r();
|
|
88
|
+
};
|
|
89
|
+
n.render(a(f, {
|
|
90
|
+
open: !0,
|
|
91
|
+
title: e.title,
|
|
92
|
+
description: e.description,
|
|
93
|
+
confirmText: e.confirmText,
|
|
94
|
+
cancelText: e.cancelText,
|
|
95
|
+
tone: e.tone,
|
|
96
|
+
loading: e.loading,
|
|
97
|
+
closeOnEsc: e.closeOnEsc,
|
|
98
|
+
closeOnBackdrop: e.closeOnBackdrop,
|
|
99
|
+
onConfirm: () => {
|
|
100
|
+
i(!0);
|
|
101
|
+
},
|
|
102
|
+
onCancel: () => {
|
|
103
|
+
i(!1);
|
|
104
|
+
}
|
|
105
|
+
}));
|
|
106
|
+
});
|
|
107
|
+
}
|
|
108
|
+
//#endregion
|
|
109
|
+
export { m as i, f as n, p as r, h as t };
|
package/dist/confirm.js
ADDED
|
@@ -0,0 +1,53 @@
|
|
|
1
|
+
/* empty css */
|
|
2
|
+
import { t as e } from "./use-modal-K9L8aPS0.js";
|
|
3
|
+
import { Fragment as t, jsx as n, jsxs as r } from "react/jsx-runtime";
|
|
4
|
+
import { createPortal as i } from "react-dom";
|
|
5
|
+
//#region src/components/dialog/Dialog.tsx
|
|
6
|
+
function a({ children: a, className: o, title: s, description: c, open: l, onClose: u, closeOnEsc: d = !0, closeOnBackdrop: f = !0, ref: p, style: m, ...h }) {
|
|
7
|
+
let { dataState: g, mounted: _, backdropRef: v, panelRef: y, titleId: b, descriptionId: x, handlePanelKeyDown: S, handleBackdropPointerDown: C } = e({
|
|
8
|
+
open: l,
|
|
9
|
+
onClose: u,
|
|
10
|
+
closeOnEsc: d,
|
|
11
|
+
closeOnBackdrop: f
|
|
12
|
+
});
|
|
13
|
+
if (!_ || typeof document > "u") return null;
|
|
14
|
+
let w = ["hn-dialog__panel", o].filter(Boolean).join(" "), T = s === void 0 ? void 0 : b, E = c === void 0 ? void 0 : x, D = (e) => {
|
|
15
|
+
y.current = e, typeof p == "function" ? p(e) : p != null && (p.current = e);
|
|
16
|
+
};
|
|
17
|
+
return i(/* @__PURE__ */ r(t, { children: [/* @__PURE__ */ n("div", {
|
|
18
|
+
className: "hn-dialog__backdrop",
|
|
19
|
+
"data-state": g,
|
|
20
|
+
onPointerDown: C,
|
|
21
|
+
ref: v
|
|
22
|
+
}), /* @__PURE__ */ r("div", {
|
|
23
|
+
...h,
|
|
24
|
+
"aria-describedby": E,
|
|
25
|
+
"aria-labelledby": T,
|
|
26
|
+
"aria-modal": "true",
|
|
27
|
+
className: w,
|
|
28
|
+
"data-state": g,
|
|
29
|
+
onKeyDown: S,
|
|
30
|
+
ref: D,
|
|
31
|
+
role: "dialog",
|
|
32
|
+
style: m,
|
|
33
|
+
tabIndex: -1,
|
|
34
|
+
children: [
|
|
35
|
+
s === void 0 ? null : /* @__PURE__ */ n("h2", {
|
|
36
|
+
className: "hn-dialog__title",
|
|
37
|
+
id: b,
|
|
38
|
+
children: s
|
|
39
|
+
}),
|
|
40
|
+
c === void 0 ? null : /* @__PURE__ */ n("p", {
|
|
41
|
+
className: "hn-dialog__description",
|
|
42
|
+
id: x,
|
|
43
|
+
children: c
|
|
44
|
+
}),
|
|
45
|
+
/* @__PURE__ */ n("div", {
|
|
46
|
+
className: "hn-dialog__content",
|
|
47
|
+
children: a
|
|
48
|
+
})
|
|
49
|
+
]
|
|
50
|
+
})] }), document.body);
|
|
51
|
+
}
|
|
52
|
+
//#endregion
|
|
53
|
+
export { a as t };
|
package/dist/dialog.d.ts
ADDED
package/dist/dialog.js
ADDED
|
@@ -0,0 +1,60 @@
|
|
|
1
|
+
/* empty css */
|
|
2
|
+
import { t as e } from "./use-modal-K9L8aPS0.js";
|
|
3
|
+
import { Fragment as t, jsx as n, jsxs as r } from "react/jsx-runtime";
|
|
4
|
+
import { createPortal as i } from "react-dom";
|
|
5
|
+
//#region src/components/drawer/Drawer.tsx
|
|
6
|
+
function a({ children: a, className: o, title: s, description: c, open: l, onClose: u, placement: d = "right", size: f, closeOnEsc: p = !0, closeOnBackdrop: m = !0, ref: h, style: g, ..._ }) {
|
|
7
|
+
let { dataState: v, mounted: y, backdropRef: b, panelRef: x, titleId: S, descriptionId: C, handlePanelKeyDown: w, handleBackdropPointerDown: T } = e({
|
|
8
|
+
open: l,
|
|
9
|
+
onClose: u,
|
|
10
|
+
closeOnEsc: p,
|
|
11
|
+
closeOnBackdrop: m
|
|
12
|
+
});
|
|
13
|
+
if (!y || typeof document > "u") return null;
|
|
14
|
+
let E = [
|
|
15
|
+
"hn-drawer__panel",
|
|
16
|
+
`hn-drawer__panel--${d}`,
|
|
17
|
+
o
|
|
18
|
+
].filter(Boolean).join(" "), D = {
|
|
19
|
+
...f === void 0 ? {} : { "--hn-drawer-size": `${String(f)}px` },
|
|
20
|
+
...g
|
|
21
|
+
}, O = s === void 0 ? void 0 : S, k = c === void 0 ? void 0 : C, A = (e) => {
|
|
22
|
+
x.current = e, typeof h == "function" ? h(e) : h != null && (h.current = e);
|
|
23
|
+
};
|
|
24
|
+
return i(/* @__PURE__ */ r(t, { children: [/* @__PURE__ */ n("div", {
|
|
25
|
+
className: "hn-drawer__backdrop",
|
|
26
|
+
"data-state": v,
|
|
27
|
+
onPointerDown: T,
|
|
28
|
+
ref: b
|
|
29
|
+
}), /* @__PURE__ */ r("div", {
|
|
30
|
+
..._,
|
|
31
|
+
"aria-describedby": k,
|
|
32
|
+
"aria-labelledby": O,
|
|
33
|
+
"aria-modal": "true",
|
|
34
|
+
className: E,
|
|
35
|
+
"data-state": v,
|
|
36
|
+
onKeyDown: w,
|
|
37
|
+
ref: A,
|
|
38
|
+
role: "dialog",
|
|
39
|
+
style: D,
|
|
40
|
+
tabIndex: -1,
|
|
41
|
+
children: [
|
|
42
|
+
s === void 0 ? null : /* @__PURE__ */ n("h2", {
|
|
43
|
+
className: "hn-drawer__title",
|
|
44
|
+
id: S,
|
|
45
|
+
children: s
|
|
46
|
+
}),
|
|
47
|
+
c === void 0 ? null : /* @__PURE__ */ n("p", {
|
|
48
|
+
className: "hn-drawer__description",
|
|
49
|
+
id: C,
|
|
50
|
+
children: c
|
|
51
|
+
}),
|
|
52
|
+
/* @__PURE__ */ n("div", {
|
|
53
|
+
className: "hn-drawer__content",
|
|
54
|
+
children: a
|
|
55
|
+
})
|
|
56
|
+
]
|
|
57
|
+
})] }), document.body);
|
|
58
|
+
}
|
|
59
|
+
//#endregion
|
|
60
|
+
export { a as t };
|
package/dist/drawer.d.ts
ADDED
package/dist/drawer.js
ADDED
|
@@ -0,0 +1,2 @@
|
|
|
1
|
+
@layer hamster-note.tokens{:root{--hn-color-surface:#111114;--hn-color-surface-hover:#17171b;--hn-color-text:#f4f4f5;--hn-color-text-muted:#92929d;--hn-color-border:#ffffff1a;--hn-color-border-strong:#ffffff2b;--hn-color-accent:#7c83ff;--hn-color-accent-hover:#9197ff;--hn-color-danger:#fb7185;--hn-color-success:#4ade80;--hn-color-warning:#fbbf24;--hn-font-sans:"IBM Plex Sans", "Noto Sans SC", sans-serif;--hn-font-mono:"IBM Plex Mono", monospace;--hn-radius-sm:6px;--hn-radius-md:8px;--hn-radius-lg:12px;--hn-focus-ring:0 0 0 3px #9197ff6b;--hn-transition:.14s cubic-bezier(.2, .8, .2, 1)}}@layer hamster-note.components{.hn-badge{border:1px solid var(--hn-color-border);border-radius:var(--hn-radius-sm);min-height:22px;font-family:var(--hn-font-mono);color:var(--hn-color-text-muted);background:#ffffff0a;align-items:center;gap:6px;padding:2px 8px;font-size:11px;font-weight:550;line-height:1.2;display:inline-flex}.hn-badge:before{content:"";background:currentColor;border-radius:50%;width:5px;height:5px}.hn-badge--accent{color:#aeb2ff;background:#7c83ff1a;border-color:#7c83ff3d}.hn-badge--success{color:var(--hn-color-success);background:#4ade8017;border-color:#4ade8038}.hn-badge--warning{color:var(--hn-color-warning);background:#fbbf2417;border-color:#fbbf2438}.hn-badge--danger{color:var(--hn-color-danger);background:#fb718517;border-color:#fb718538}.hn-button{border-radius:var(--hn-radius-md);min-height:36px;font-family:var(--hn-font-sans);color:var(--hn-color-text);cursor:pointer;transition:background-color var(--hn-transition), border-color var(--hn-transition), color var(--hn-transition), opacity var(--hn-transition);border:1px solid #0000;justify-content:center;align-items:center;gap:8px;padding:0 14px;font-size:13px;font-weight:600;line-height:1;display:inline-flex}.hn-button:focus-visible{box-shadow:var(--hn-focus-ring);outline:none}.hn-button:disabled{cursor:not-allowed;opacity:.42}.hn-button--primary{background:var(--hn-color-accent);color:#09090b}.hn-button--primary:hover:not(:disabled){background:var(--hn-color-accent-hover)}.hn-button--secondary{border-color:var(--hn-color-border);background:var(--hn-color-surface)}.hn-button--secondary:hover:not(:disabled){border-color:var(--hn-color-border-strong);background:var(--hn-color-surface-hover)}.hn-button--ghost{color:var(--hn-color-text-muted);background:0 0}.hn-button--ghost:hover:not(:disabled){background:var(--hn-color-surface-hover);color:var(--hn-color-text)}.hn-button--small{min-height:30px;padding:0 11px;font-size:12px}.hn-button--large{min-height:42px;padding:0 18px;font-size:14px}@media (prefers-reduced-motion:reduce){.hn-button{transition-duration:.01ms}}.hn-dialog__backdrop{z-index:1100;-webkit-backdrop-filter:blur(8px);background:#00000073;transition:opacity .14s cubic-bezier(.2,.8,.2,1);position:fixed;inset:0}.hn-dialog__backdrop[data-state=enter]{opacity:1}.hn-dialog__backdrop[data-state=exit]{opacity:0}.hn-dialog__panel{z-index:1100;border:1px solid var(--hn-color-border);border-radius:var(--hn-radius-lg);background:var(--hn-color-surface);width:auto;min-width:320px;max-width:calc(100vw - 32px);max-height:calc(100vh - 64px);color:var(--hn-color-text);font-family:var(--hn-font-sans);flex-direction:column;padding:20px 24px;transition:opacity .14s cubic-bezier(.2,.8,.2,1),transform .18s cubic-bezier(.2,.8,.2,1);display:flex;position:fixed;top:50%;left:50%;transform:translate(-50%,-50%);box-shadow:0 16px 48px #00000052}.hn-dialog__panel[data-state=enter]{opacity:1;transform:translate(-50%,-50%)}.hn-dialog__panel[data-state=exit],.hn-dialog__panel{opacity:0;transform:translate(-50%,calc(8px - 50%))}.hn-dialog__panel:focus-visible{box-shadow:var(--hn-focus-ring), 0 16px 48px #00000052;outline:none}.hn-dialog__title{letter-spacing:-.01em;color:var(--hn-color-text);margin:0 0 4px;font-size:18px;font-weight:550;line-height:1.45}.hn-dialog__description{color:var(--hn-color-text-muted);margin:0;font-size:13px;line-height:1.65}.hn-dialog__content{margin-top:16px}.hn-dialog__panel:not(:has(.hn-dialog__title)) .hn-dialog__content{margin-top:0}@media (prefers-reduced-motion:reduce){.hn-dialog__backdrop,.hn-dialog__panel{transition-duration:.01ms}}.hn-confirm__footer{justify-content:flex-end;gap:8px;margin-top:20px;display:flex}.hn-confirm__footer[data-tone=danger] .hn-button--primary{background:var(--hn-color-danger);color:#09090b}.hn-confirm__footer[data-tone=danger] .hn-button--primary:hover:not(:disabled){background:color-mix(in srgb, var(--hn-color-danger) 88%, white)}.hn-drawer__backdrop{z-index:1200;-webkit-backdrop-filter:blur(8px);background:#00000073;transition:opacity .14s cubic-bezier(.2,.8,.2,1);position:fixed;inset:0}.hn-drawer__backdrop[data-state=enter]{opacity:1}.hn-drawer__backdrop[data-state=exit]{opacity:0}.hn-drawer__panel{z-index:1200;border:1px solid var(--hn-color-border);background:var(--hn-color-surface);max-width:100vw;max-height:100vh;color:var(--hn-color-text);font-family:var(--hn-font-sans);opacity:0;flex-direction:column;padding:20px 24px;transition:opacity .14s cubic-bezier(.2,.8,.2,1),transform .18s cubic-bezier(.2,.8,.2,1);display:flex;position:fixed;box-shadow:0 16px 48px #00000052}.hn-drawer__panel:focus-visible{box-shadow:var(--hn-focus-ring), 0 16px 48px #00000052;outline:none}.hn-drawer__panel--left,.hn-drawer__panel--right{width:var(--hn-drawer-size,360px);max-width:100vw;height:100vh;top:0;bottom:0}.hn-drawer__panel--left{border-radius:0 var(--hn-radius-lg) var(--hn-radius-lg) 0;left:0;transform:translate(-100%)}.hn-drawer__panel--right{border-radius:var(--hn-radius-lg) 0 0 var(--hn-radius-lg);right:0;transform:translate(100%)}.hn-drawer__panel--left[data-state=enter],.hn-drawer__panel--right[data-state=enter]{opacity:1;transform:translate(0)}.hn-drawer__panel--left[data-state=exit]{opacity:0;transform:translate(-100%)}.hn-drawer__panel--right[data-state=exit]{opacity:0;transform:translate(100%)}.hn-drawer__panel--top,.hn-drawer__panel--bottom{width:100vw;height:var(--hn-drawer-size,280px);max-height:100vh;left:0;right:0}.hn-drawer__panel--top{border-radius:0 0 var(--hn-radius-lg) var(--hn-radius-lg);top:0;transform:translateY(-100%)}.hn-drawer__panel--bottom{border-radius:var(--hn-radius-lg) var(--hn-radius-lg) 0 0;bottom:0;transform:translateY(100%)}.hn-drawer__panel--top[data-state=enter],.hn-drawer__panel--bottom[data-state=enter]{opacity:1;transform:translateY(0)}.hn-drawer__panel--top[data-state=exit]{opacity:0;transform:translateY(-100%)}.hn-drawer__panel--bottom[data-state=exit]{opacity:0;transform:translateY(100%)}.hn-drawer__title{letter-spacing:-.01em;color:var(--hn-color-text);margin:0 0 4px;font-size:18px;font-weight:550;line-height:1.45}.hn-drawer__description{color:var(--hn-color-text-muted);margin:0;font-size:13px;line-height:1.65}.hn-drawer__content{flex:auto;margin-top:16px;overflow:auto}.hn-drawer__panel:not(:has(.hn-drawer__title)) .hn-drawer__content{margin-top:0}@media (prefers-reduced-motion:reduce){.hn-drawer__backdrop,.hn-drawer__panel{transition-duration:.01ms}}.hn-icon{vertical-align:-.125em;pointer-events:none;flex-shrink:0;justify-content:center;align-items:center;line-height:0;display:inline-flex}.hn-kbd{font-family:var(--hn-font-mono);color:var(--hn-color-text);white-space:nowrap;vertical-align:baseline;align-items:center;gap:4px;font-size:11px;line-height:1;display:inline-flex}.hn-kbd__key{border:1px solid color-mix(in srgb, var(--hn-color-text) 22%, transparent);border-radius:var(--hn-radius-sm);background:var(--hn-color-surface-hover);min-width:18px;color:var(--hn-color-text);vertical-align:baseline;white-space:nowrap;-webkit-user-select:none;user-select:none;justify-content:center;align-items:center;padding:2px 6px;font-family:inherit;font-size:11px;font-weight:500;line-height:1;display:inline-flex;box-shadow:inset 0 -1px #0000001f}.hn-kbd__plus{color:var(--hn-color-text-muted);-webkit-user-select:none;user-select:none;font-family:inherit;font-size:11px;font-weight:400;line-height:1}.hn-loading{color:var(--hn-color-accent);font-family:var(--hn-font-sans);justify-content:center;align-items:center;gap:8px;line-height:0;display:inline-flex}.hn-loading__spinner{animation:hn-loading-spin var(--hn-loading-duration,.9s) linear infinite;transform-origin:50%;flex-shrink:0;display:block}.hn-loading__text{color:var(--hn-color-text-muted);white-space:nowrap;font-size:13px;line-height:1.5}.hn-loading--small .hn-loading__text{font-size:12px}.hn-loading--large .hn-loading__text{font-size:14px}.hn-loading--cover{background:color-mix(in srgb, var(--hn-color-surface) 72%, transparent);-webkit-backdrop-filter:blur(2px);border-radius:inherit;color:var(--hn-color-accent);flex-direction:column;gap:12px;position:absolute;inset:0}.hn-loading--cover .hn-loading__text{color:var(--hn-color-text)}.hn-loading-overlay{z-index:1200;-webkit-backdrop-filter:blur(8px);color:var(--hn-color-accent);font-family:var(--hn-font-sans);background:#00000073;flex-direction:column;justify-content:center;align-items:center;gap:14px;animation:.14s cubic-bezier(.2,.8,.2,1) hn-loading-overlay-fade;display:flex;position:fixed;inset:0}.hn-loading-overlay .hn-loading__text{color:var(--hn-color-text);font-size:14px}@keyframes hn-loading-spin{to{transform:rotate(360deg)}}@keyframes hn-loading-overlay-fade{0%{opacity:0}to{opacity:1}}@media (prefers-reduced-motion:reduce){.hn-loading__spinner{animation-duration:2.4s;animation-timing-function:steps(12,end)}.hn-loading-overlay{animation-duration:.01ms}}.hn-popover{--hn-popover-background:#1e293bcc;--hn-popover-border:#ffffff1a;--hn-popover-separator:#ffffff2e;--hn-color-surface-hover:#ffffff1a;--hn-color-text:#f8fafc;--hn-color-text-muted:#cbd5e1;--hn-popover-padding:5px;max-width:100%;padding:var(--hn-popover-padding);border:1px solid var(--hn-popover-border);border-radius:calc(var(--hn-radius-md) + var(--hn-popover-padding));background:var(--hn-popover-background);-webkit-backdrop-filter:blur(12px);color:var(--hn-color-text);font-family:var(--hn-font-sans);align-items:center;gap:3px;display:inline-flex;box-shadow:0 8px 24px #0f172a47}.hn-popover[data-theme=light]{--hn-popover-background:#fffc;--hn-popover-border:#0f172a1f;--hn-popover-separator:#0f172a29;--hn-color-surface-hover:#f1f5f9;--hn-color-text:#1e293b;--hn-color-text-muted:#64748b;box-shadow:0 8px 24px #0f172a29}.hn-popover--floating{z-index:1000}.hn-popover[data-orientation=vertical]{flex-direction:column}.hn-popover__separator{background:var(--hn-popover-separator);border:0;flex:0 0 1px;width:1px;height:20px;margin:0 4px;padding:0}.hn-popover[data-orientation=vertical] .hn-popover__separator{flex:0 0 1px;width:20px;height:1px;margin:4px 0}.hn-menu{min-width:180px;font-family:var(--hn-font-sans);color:var(--hn-color-text);-webkit-backdrop-filter:blur(12px);border-radius:var(--hn-radius-md);background:#1e293bcc;flex-direction:column;gap:2px;padding:4px;display:flex}.hn-menu__item{border-radius:var(--hn-radius-md);width:100%;min-height:32px;color:var(--hn-color-text);cursor:pointer;text-align:left;transition:background-color var(--hn-transition), color var(--hn-transition);background:0 0;border:0;justify-content:space-between;align-items:center;gap:12px;padding:0 10px;font-size:13px;line-height:1;display:flex}.hn-menu__item:hover:not(:disabled){background:var(--hn-color-surface-hover)}.hn-menu__item:focus-visible{box-shadow:var(--hn-focus-ring);outline:none}.hn-menu__item:disabled{cursor:not-allowed;opacity:.42}.hn-menu__item--danger{color:var(--hn-color-danger)}.hn-menu__item-label{flex:auto;min-width:0}.hn-menu__shortcut{font:400 11px/1 var(--hn-font-mono);color:var(--hn-color-text-muted);flex-shrink:0;align-items:center;display:inline-flex}.hn-menu__separator{background:var(--hn-popover-separator,var(--hn-color-border));border:0;height:1px;margin:4px 2px}.hn-menu__label{color:var(--hn-color-text-muted);-webkit-user-select:none;user-select:none;padding:4px 10px 2px;font-size:11px;line-height:1}.hn-menu__submenu{display:block}.hn-menu__submenu--open>.hn-menu__submenu-trigger{background:var(--hn-color-surface-hover)}.hn-menu__submenu-chevron{font:400 11px/1 var(--hn-font-sans);color:var(--hn-color-text-muted);transition:transform var(--hn-transition);flex-shrink:0;align-items:center;display:inline-flex}.hn-menu__submenu--open>.hn-menu__submenu-trigger .hn-menu__submenu-chevron{transform:rotate(90deg)}.hn-menu__submenu-panel{z-index:1000}.hn-menu__submenu-panel .hn-menu{min-width:160px}@media (prefers-reduced-motion:reduce){.hn-menu__item,.hn-menu__submenu-chevron{transition-duration:.01ms}}.hn-note-card{box-sizing:border-box;border:1px solid var(--hn-color-border);border-radius:var(--hn-radius-lg);background:var(--hn-color-surface);width:100%;font-family:var(--hn-font-sans);color:var(--hn-color-text);text-align:left;transition:background-color var(--hn-transition), border-color var(--hn-transition), transform .18s cubic-bezier(.2, .8, .2, 1);gap:14px;padding:18px;display:grid;position:relative}.hn-note-card__action{z-index:1;border-radius:inherit;cursor:pointer;background:0 0;border:0;position:absolute;inset:0}.hn-note-card--interactive:has(.hn-note-card__action:hover){border-color:var(--hn-color-border-strong);background:var(--hn-color-surface-hover);transform:translateY(-1px)}.hn-note-card--interactive:has(.hn-note-card__action:focus-visible){box-shadow:var(--hn-focus-ring);outline:none}.hn-note-card__action:focus-visible{outline:none}.hn-note-card--selected{background:#7c83ff14;border-color:#7c83ff73}.hn-note-card__heading{gap:5px;display:grid}.hn-note-card__title,.hn-note-card__excerpt,.hn-note-card__meta{margin:0}.hn-note-card__title{letter-spacing:-.01em;font-size:15px;font-weight:600;line-height:1.35}.hn-note-card__excerpt{color:var(--hn-color-text-muted);text-wrap:pretty;font-size:13px;line-height:1.6}.hn-note-card__meta{font-family:var(--hn-font-mono);color:#70707b;font-size:11px;line-height:1.4}@media (prefers-reduced-motion:reduce){.hn-note-card{transition-duration:.01ms}}.hn-text-field{width:100%;font-family:var(--hn-font-sans);gap:7px;display:grid}.hn-text-field__label{color:var(--hn-color-text);font-size:12px;font-weight:600;line-height:1.3}.hn-text-field__control{box-sizing:border-box;border:1px solid var(--hn-color-border);border-radius:var(--hn-radius-md);background:var(--hn-color-surface);width:100%;min-height:38px;font:400 14px/1.4 var(--hn-font-sans);color:var(--hn-color-text);transition:border-color var(--hn-transition), background-color var(--hn-transition), box-shadow var(--hn-transition);outline:none;padding:8px 11px}.hn-text-field__control::placeholder{color:#666670}.hn-text-field__control:hover:not(:disabled){border-color:var(--hn-color-border-strong)}.hn-text-field__control:focus-visible{border-color:var(--hn-color-accent);background:var(--hn-color-surface-hover);box-shadow:var(--hn-focus-ring);outline:none}.hn-text-field__control:disabled{cursor:not-allowed;opacity:.48}.hn-text-field--invalid .hn-text-field__control{border-color:#fb718599}.hn-text-field__message{color:var(--hn-color-text-muted);margin:0;font-size:12px;line-height:1.4}.hn-text-field--invalid .hn-text-field__message{color:var(--hn-color-danger)}@media (prefers-reduced-motion:reduce){.hn-text-field__control{transition-duration:.01ms}}.hn-theme{display:contents}.hn-theme[data-accent=custom]{--hn-color-accent-hover:color-mix(in srgb, var(--hn-color-accent), #fff 16%);--hn-focus-ring:0 0 0 3px color-mix(in srgb, var(--hn-color-accent) 42%, transparent)}}.hn-theme[data-mode=light]{--hn-color-surface:#fff;--hn-color-surface-hover:#f4f4f6;--hn-color-text:#18181b;--hn-color-text-muted:#63636d;--hn-color-border:#0000001a;--hn-color-border-strong:#0000002e;--hn-color-danger:#e11d48;--hn-color-success:#16a34a;--hn-color-warning:#d97706}.hn-theme[data-mode=dark]{--hn-color-surface:#111114;--hn-color-surface-hover:#17171b;--hn-color-text:#f4f4f5;--hn-color-text-muted:#92929d;--hn-color-border:#ffffff1a;--hn-color-border-strong:#ffffff2b;--hn-color-danger:#fb7185;--hn-color-success:#4ade80;--hn-color-warning:#fbbf24}
|
|
2
|
+
/*$vite$:1*/
|