@adecore/ui 0.16.0 → 0.17.0-beta.2
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 +97 -8
- package/README.md +1 -1
- package/dist/Select.js +2 -1
- package/dist/file-tree/helpers.d.ts +42 -0
- package/dist/file-tree/helpers.js +167 -0
- package/dist/file-tree/index.parts.d.ts +3 -0
- package/dist/file-tree/index.parts.js +3 -0
- package/dist/file-tree/parts.d.ts +20 -0
- package/dist/file-tree/parts.js +150 -0
- package/dist/file-tree/shift.d.ts +15 -0
- package/dist/file-tree/shift.js +34 -0
- package/dist/file-tree/style.d.ts +1 -0
- package/dist/file-tree/style.js +24 -0
- package/dist/file-tree/use-file-tree-shift.d.ts +6 -0
- package/dist/file-tree/use-file-tree-shift.js +142 -0
- package/dist/file-tree/use-file-tree.d.ts +5 -0
- package/dist/file-tree/use-file-tree.js +26 -0
- package/dist/file-tree/use-slots.d.ts +7 -0
- package/dist/file-tree/use-slots.js +171 -0
- package/dist/index.d.ts +7 -0
- package/dist/index.js +3 -0
- package/dist/locales/en.json +5 -0
- package/dist/locales/nl.json +5 -0
- package/dist/menu/parts.js +2 -1
- package/dist/popover/parts.js +2 -1
- package/dist/popup-layer.d.ts +6 -0
- package/dist/popup-layer.js +30 -0
- package/dist/theme.css +104 -1
- package/dist/tree/index.parts.d.ts +1 -0
- package/dist/tree/index.parts.js +1 -0
- package/dist/tree/parts.d.ts +27 -0
- package/dist/tree/parts.js +113 -0
- package/dist/tree/style.d.ts +2 -0
- package/dist/tree/style.js +29 -0
- package/package.json +6 -4
- package/src/Select.tsx +9 -1
- package/src/file-tree/helpers.ts +203 -0
- package/src/file-tree/index.parts.ts +25 -0
- package/src/file-tree/parts.tsx +206 -0
- package/src/file-tree/shift.ts +48 -0
- package/src/file-tree/style.ts +25 -0
- package/src/file-tree/use-file-tree-shift.tsx +169 -0
- package/src/file-tree/use-file-tree.ts +31 -0
- package/src/file-tree/use-slots.ts +191 -0
- package/src/index.ts +17 -0
- package/src/locales/en.json +5 -0
- package/src/locales/nl.json +5 -0
- package/src/menu/parts.tsx +2 -0
- package/src/popover/parts.tsx +2 -0
- package/src/popup-layer.ts +34 -0
- package/src/theme.css +104 -1
- package/src/tree/index.parts.ts +10 -0
- package/src/tree/parts.tsx +170 -0
- package/src/tree/style.ts +30 -0
|
@@ -0,0 +1,170 @@
|
|
|
1
|
+
import type { MouseEvent, KeyboardEvent, PointerEvent } from 'react';
|
|
2
|
+
import clsx from 'clsx';
|
|
3
|
+
import { useRender } from '@base-ui-components/react/use-render';
|
|
4
|
+
import { ChevronRight } from 'lucide-react';
|
|
5
|
+
import { useTranslation } from 'react-i18next';
|
|
6
|
+
import { Checkbox as UICheckbox, type CheckboxProps } from '../Checkbox.tsx';
|
|
7
|
+
import { Icon } from '../Icon.tsx';
|
|
8
|
+
import { treeRowStyle } from './style.ts';
|
|
9
|
+
|
|
10
|
+
export type TreeRootProps = useRender.ComponentProps<'div'>;
|
|
11
|
+
|
|
12
|
+
export function TreeRoot({ render, className, ref, children, ...props }: TreeRootProps) {
|
|
13
|
+
return useRender({
|
|
14
|
+
render,
|
|
15
|
+
ref,
|
|
16
|
+
defaultTagName: 'div',
|
|
17
|
+
props: {
|
|
18
|
+
role: 'tree',
|
|
19
|
+
...props,
|
|
20
|
+
className: clsx('adecore-tree', className),
|
|
21
|
+
children: (
|
|
22
|
+
<>
|
|
23
|
+
<style>{treeRowStyle('.adecore-tree-row')}</style>
|
|
24
|
+
{children}
|
|
25
|
+
</>
|
|
26
|
+
)
|
|
27
|
+
}
|
|
28
|
+
});
|
|
29
|
+
}
|
|
30
|
+
|
|
31
|
+
export type TreeRowProps = useRender.ComponentProps<'div'> & {
|
|
32
|
+
level?: number;
|
|
33
|
+
selected?: boolean;
|
|
34
|
+
joinedStart?: boolean;
|
|
35
|
+
joinedEnd?: boolean;
|
|
36
|
+
interactive?: boolean;
|
|
37
|
+
};
|
|
38
|
+
|
|
39
|
+
export function TreeRow({
|
|
40
|
+
level = 1,
|
|
41
|
+
selected = false,
|
|
42
|
+
joinedStart = false,
|
|
43
|
+
joinedEnd = false,
|
|
44
|
+
interactive = true,
|
|
45
|
+
render,
|
|
46
|
+
className,
|
|
47
|
+
ref,
|
|
48
|
+
style,
|
|
49
|
+
children,
|
|
50
|
+
...props
|
|
51
|
+
}: TreeRowProps) {
|
|
52
|
+
return useRender({
|
|
53
|
+
render,
|
|
54
|
+
ref,
|
|
55
|
+
defaultTagName: 'div',
|
|
56
|
+
props: {
|
|
57
|
+
role: 'treeitem',
|
|
58
|
+
'aria-level': level,
|
|
59
|
+
'aria-selected': selected,
|
|
60
|
+
...props,
|
|
61
|
+
'data-selected': selected,
|
|
62
|
+
'data-joined-start': joinedStart,
|
|
63
|
+
'data-joined-end': joinedEnd,
|
|
64
|
+
'data-interactive': interactive,
|
|
65
|
+
className: clsx('adecore-tree-row', className),
|
|
66
|
+
style: { paddingInlineStart: 4 + (Math.max(1, level) - 1) * 16, ...style },
|
|
67
|
+
children: (
|
|
68
|
+
<>
|
|
69
|
+
{Array.from({ length: Math.max(0, level - 1) }, (_, index) => (
|
|
70
|
+
<span key={index} aria-hidden className="adecore-tree-guide" style={{ insetInlineStart: 11 + index * 16 }} />
|
|
71
|
+
))}
|
|
72
|
+
{children}
|
|
73
|
+
</>
|
|
74
|
+
)
|
|
75
|
+
}
|
|
76
|
+
});
|
|
77
|
+
}
|
|
78
|
+
|
|
79
|
+
export type TreeChevronSlotProps = useRender.ComponentProps<'span'>;
|
|
80
|
+
|
|
81
|
+
export function TreeChevronSlot({ render, className, ref, ...props }: TreeChevronSlotProps) {
|
|
82
|
+
return useRender({
|
|
83
|
+
render,
|
|
84
|
+
ref,
|
|
85
|
+
defaultTagName: 'span',
|
|
86
|
+
props: { 'aria-hidden': true, ...props, className: clsx('adecore-tree-chevron-slot', className) }
|
|
87
|
+
});
|
|
88
|
+
}
|
|
89
|
+
|
|
90
|
+
export type TreeChevronProps = useRender.ComponentProps<'button'> & {
|
|
91
|
+
expanded: boolean;
|
|
92
|
+
onExpandedChange?(expanded: boolean): void;
|
|
93
|
+
};
|
|
94
|
+
|
|
95
|
+
export function TreeChevron({ expanded, onExpandedChange, render, className, ref, onClick, onDoubleClick, ...props }: TreeChevronProps) {
|
|
96
|
+
const { t } = useTranslation('ui');
|
|
97
|
+
return useRender({
|
|
98
|
+
render,
|
|
99
|
+
ref,
|
|
100
|
+
defaultTagName: 'button',
|
|
101
|
+
props: {
|
|
102
|
+
type: 'button',
|
|
103
|
+
tabIndex: -1,
|
|
104
|
+
'aria-label': t(expanded ? 'tree.collapse' : 'tree.expand'),
|
|
105
|
+
...props,
|
|
106
|
+
className: clsx('adecore-tree-chevron-slot', className),
|
|
107
|
+
onClick: (event: MouseEvent<HTMLButtonElement>) => {
|
|
108
|
+
event.stopPropagation();
|
|
109
|
+
onClick?.(event);
|
|
110
|
+
if (!event.defaultPrevented) {
|
|
111
|
+
onExpandedChange?.(!expanded);
|
|
112
|
+
}
|
|
113
|
+
},
|
|
114
|
+
onDoubleClick: (event: MouseEvent<HTMLButtonElement>) => {
|
|
115
|
+
event.stopPropagation();
|
|
116
|
+
onDoubleClick?.(event);
|
|
117
|
+
},
|
|
118
|
+
children: <Icon icon={ChevronRight} size={12} className={expanded ? 'rotate-90' : undefined} />
|
|
119
|
+
}
|
|
120
|
+
});
|
|
121
|
+
}
|
|
122
|
+
|
|
123
|
+
export type TreeLabelProps = useRender.ComponentProps<'span'>;
|
|
124
|
+
export function TreeLabel({ render, className, ref, ...props }: TreeLabelProps) {
|
|
125
|
+
return useRender({ render, ref, defaultTagName: 'span', props: { ...props, className: clsx('adecore-tree-label', className) } });
|
|
126
|
+
}
|
|
127
|
+
|
|
128
|
+
export type TreeDecorationProps = useRender.ComponentProps<'span'>;
|
|
129
|
+
export function TreeDecoration({ render, className, ref, ...props }: TreeDecorationProps) {
|
|
130
|
+
return useRender({ render, ref, defaultTagName: 'span', props: { ...props, className: clsx('adecore-tree-decoration', className) } });
|
|
131
|
+
}
|
|
132
|
+
|
|
133
|
+
export type TreeControlProps = useRender.ComponentProps<'span'>;
|
|
134
|
+
export function TreeControl({ render, className, ref, onClick, onDoubleClick, onKeyDown, onPointerDown, ...props }: TreeControlProps) {
|
|
135
|
+
return useRender({
|
|
136
|
+
render,
|
|
137
|
+
ref,
|
|
138
|
+
defaultTagName: 'span',
|
|
139
|
+
props: {
|
|
140
|
+
...props,
|
|
141
|
+
'data-tree-control': true,
|
|
142
|
+
className: clsx('adecore-tree-control', className),
|
|
143
|
+
onClick: (event: MouseEvent<HTMLSpanElement>) => {
|
|
144
|
+
event.stopPropagation();
|
|
145
|
+
onClick?.(event);
|
|
146
|
+
},
|
|
147
|
+
onDoubleClick: (event: MouseEvent<HTMLSpanElement>) => {
|
|
148
|
+
event.stopPropagation();
|
|
149
|
+
onDoubleClick?.(event);
|
|
150
|
+
},
|
|
151
|
+
onKeyDown: (event: KeyboardEvent<HTMLSpanElement>) => {
|
|
152
|
+
event.stopPropagation();
|
|
153
|
+
onKeyDown?.(event);
|
|
154
|
+
},
|
|
155
|
+
onPointerDown: (event: PointerEvent<HTMLSpanElement>) => {
|
|
156
|
+
event.stopPropagation();
|
|
157
|
+
onPointerDown?.(event);
|
|
158
|
+
}
|
|
159
|
+
}
|
|
160
|
+
});
|
|
161
|
+
}
|
|
162
|
+
|
|
163
|
+
export type TreeCheckboxProps = CheckboxProps;
|
|
164
|
+
export function TreeCheckbox(props: TreeCheckboxProps) {
|
|
165
|
+
return (
|
|
166
|
+
<TreeControl>
|
|
167
|
+
<UICheckbox {...props} />
|
|
168
|
+
</TreeControl>
|
|
169
|
+
);
|
|
170
|
+
}
|
|
@@ -0,0 +1,30 @@
|
|
|
1
|
+
export const TREE_ROW_HEIGHT = 25;
|
|
2
|
+
|
|
3
|
+
export function treeRowStyle(selector: string, selected = 'data-selected'): string {
|
|
4
|
+
return `
|
|
5
|
+
${selector} {
|
|
6
|
+
box-sizing: border-box;
|
|
7
|
+
display: flex;
|
|
8
|
+
position: relative;
|
|
9
|
+
align-items: center;
|
|
10
|
+
height: var(--tree-row-height, 25px);
|
|
11
|
+
min-width: 0;
|
|
12
|
+
gap: var(--tree-row-gap, 6px);
|
|
13
|
+
border: 0;
|
|
14
|
+
border-radius: var(--tree-row-radius, 6px);
|
|
15
|
+
background: transparent;
|
|
16
|
+
background-clip: padding-box;
|
|
17
|
+
color: var(--text);
|
|
18
|
+
font-family: var(--font-sans);
|
|
19
|
+
font-size: var(--text-xs);
|
|
20
|
+
line-height: var(--tree-row-height, 25px);
|
|
21
|
+
text-align: start;
|
|
22
|
+
outline: none;
|
|
23
|
+
}
|
|
24
|
+
${selector}[data-interactive="true"]:hover { background: var(--surface-hover); }
|
|
25
|
+
${selector}[${selected}="true"] { background: var(--surface-active); color: var(--text); }
|
|
26
|
+
${selector}[data-joined-start="true"] { border-start-start-radius: 0; border-start-end-radius: 0; }
|
|
27
|
+
${selector}[data-joined-end="true"] { border-end-start-radius: 0; border-end-end-radius: 0; }
|
|
28
|
+
${selector}:focus-visible { outline: 2px solid var(--accent); outline-offset: -2px; }
|
|
29
|
+
`;
|
|
30
|
+
}
|