@noya-app/noya-designsystem 0.1.94 → 0.1.96
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/.turbo/turbo-build.log +9 -9
- package/.turbo/turbo-typecheck.log +1 -0
- package/CHANGELOG.md +16 -0
- package/dist/index.css +1 -1
- package/dist/index.d.mts +158 -93
- package/dist/index.d.ts +158 -93
- package/dist/index.js +1307 -1034
- package/dist/index.js.map +1 -1
- package/dist/index.mjs +1231 -962
- package/dist/index.mjs.map +1 -1
- package/package.json +6 -5
- package/src/__tests__/SharedDragProvider.test.ts +72 -29
- package/src/__tests__/fuzzyScorer.test.ts +49 -1
- package/src/components/Button.tsx +1 -1
- package/src/components/Combobox.tsx +23 -3
- package/src/components/ComboboxMenu.tsx +32 -15
- package/src/components/ContextMenu.tsx +26 -7
- package/src/components/DimensionInput.tsx +12 -2
- package/src/components/DropdownMenu.tsx +23 -8
- package/src/components/InputField.tsx +1 -0
- package/src/components/InspectorContainer.tsx +16 -1
- package/src/components/List.tsx +25 -3
- package/src/components/Popover.tsx +13 -1
- package/src/components/Section.tsx +35 -11
- package/src/components/SegmentedControl.tsx +14 -4
- package/src/components/Toolbar.tsx +16 -1
- package/src/components/ToolbarItems.tsx +322 -0
- package/src/components/Tooltip.tsx +8 -1
- package/src/components/__tests__/Card.test.tsx +2 -1
- package/src/components/__tests__/InputField.test.tsx +3 -1
- package/src/components/__tests__/ToolbarItems.test.tsx +205 -0
- package/src/components/internal/Menu.tsx +4 -1
- package/src/components/internal/TextInput.tsx +43 -2
- package/src/components/internal/__tests__/TextInput.test.tsx +79 -2
- package/src/components/listView/ListViewEditableRowTitle.tsx +37 -1
- package/src/components/listView/ListViewRow.tsx +3 -0
- package/src/components/listView/__tests__/ListViewEditableRowTitle.test.tsx +69 -0
- package/src/components/sorting/Sortable.tsx +4 -1
- package/src/index.tsx +0 -1
- package/src/utils/combobox.ts +22 -5
- package/src/utils/fuzzyScorer.ts +71 -0
- package/tailwind.config.ts +7 -0
- package/src/components/InspectorPrimitives.tsx +0 -188
package/src/utils/fuzzyScorer.ts
CHANGED
|
@@ -31,6 +31,77 @@ export function fuzzyFilter({
|
|
|
31
31
|
.sort((a, b) => b.score - a.score);
|
|
32
32
|
}
|
|
33
33
|
|
|
34
|
+
/**
|
|
35
|
+
* Word-boundary filter for name-like lists (e.g. font families): ranks
|
|
36
|
+
* exact > prefix > word-start matches and only falls back to substring
|
|
37
|
+
* matches when nothing matches at a word boundary. Prevents queries like
|
|
38
|
+
* "Play" from surfacing every "* Display" family via mid-word substrings.
|
|
39
|
+
*/
|
|
40
|
+
export function wordPrefixFilter({
|
|
41
|
+
items,
|
|
42
|
+
query,
|
|
43
|
+
}: {
|
|
44
|
+
items: string[];
|
|
45
|
+
query: string;
|
|
46
|
+
}): IScoredItem[] {
|
|
47
|
+
const normalizedQuery = query.trim().toLowerCase();
|
|
48
|
+
|
|
49
|
+
if (!normalizedQuery) {
|
|
50
|
+
return items.map((_, index): IScoredItem => ({ index, score: 0 }));
|
|
51
|
+
}
|
|
52
|
+
|
|
53
|
+
const boundaryMatches: IScoredItem[] = [];
|
|
54
|
+
const substringMatches: IScoredItem[] = [];
|
|
55
|
+
|
|
56
|
+
items.forEach((text, index) => {
|
|
57
|
+
const lower = text.toLowerCase();
|
|
58
|
+
|
|
59
|
+
const makeItem = (score: number, start: number): IScoredItem => ({
|
|
60
|
+
index,
|
|
61
|
+
score,
|
|
62
|
+
labelMatch: [{ start, end: start + normalizedQuery.length }],
|
|
63
|
+
});
|
|
64
|
+
|
|
65
|
+
if (lower === normalizedQuery) {
|
|
66
|
+
boundaryMatches.push({
|
|
67
|
+
index,
|
|
68
|
+
score: 4000,
|
|
69
|
+
labelMatch: [{ start: 0, end: text.length }],
|
|
70
|
+
});
|
|
71
|
+
return;
|
|
72
|
+
}
|
|
73
|
+
|
|
74
|
+
if (lower.startsWith(normalizedQuery)) {
|
|
75
|
+
boundaryMatches.push(makeItem(3000, 0));
|
|
76
|
+
return;
|
|
77
|
+
}
|
|
78
|
+
|
|
79
|
+
// Match at the start of any subsequent word (space/hyphen separated)
|
|
80
|
+
const wordStart = lower.search(
|
|
81
|
+
new RegExp(`[\\s-]${escapeRegExp(normalizedQuery)}`)
|
|
82
|
+
);
|
|
83
|
+
if (wordStart !== -1) {
|
|
84
|
+
boundaryMatches.push(makeItem(2000 - wordStart, wordStart + 1));
|
|
85
|
+
return;
|
|
86
|
+
}
|
|
87
|
+
|
|
88
|
+
const substringIndex = lower.indexOf(normalizedQuery);
|
|
89
|
+
if (substringIndex !== -1) {
|
|
90
|
+
substringMatches.push(makeItem(1, substringIndex));
|
|
91
|
+
}
|
|
92
|
+
});
|
|
93
|
+
|
|
94
|
+
// Only fall back to mid-word substring matches when nothing matched at a
|
|
95
|
+
// word boundary.
|
|
96
|
+
const result = boundaryMatches.length > 0 ? boundaryMatches : substringMatches;
|
|
97
|
+
|
|
98
|
+
return result.sort((a, b) => b.score - a.score);
|
|
99
|
+
}
|
|
100
|
+
|
|
101
|
+
function escapeRegExp(value: string): string {
|
|
102
|
+
return value.replace(/[.*+?^${}()|[\]\\]/g, "\\$&");
|
|
103
|
+
}
|
|
104
|
+
|
|
34
105
|
export type IToken =
|
|
35
106
|
| { type: "text"; text: string }
|
|
36
107
|
| { type: "match"; text: string };
|
package/tailwind.config.ts
CHANGED
|
@@ -5,6 +5,13 @@ import type { Config } from "tailwindcss";
|
|
|
5
5
|
|
|
6
6
|
const config = {
|
|
7
7
|
...noyaConfig,
|
|
8
|
+
// Tailwind class names are confined to the packages that generate CSS: this
|
|
9
|
+
// package and @noya-app/inspector. The inspector package ships no Tailwind
|
|
10
|
+
// build of its own — its classes are generated here and reach apps through
|
|
11
|
+
// the dist/index.css that @noya-app/inspector re-exports/imports — so its
|
|
12
|
+
// sources are part of this build's content. Consuming packages/apps compose
|
|
13
|
+
// styled components instead of writing raw class names for them.
|
|
14
|
+
content: ["./src/**/*.{ts,tsx}", "../inspector/src/**/*.{ts,tsx}"],
|
|
8
15
|
prefix: "n-",
|
|
9
16
|
plugins: [containerQueries, typography],
|
|
10
17
|
safelist: [
|
|
@@ -1,188 +0,0 @@
|
|
|
1
|
-
import React, {
|
|
2
|
-
ForwardedRef,
|
|
3
|
-
forwardRef,
|
|
4
|
-
LabelHTMLAttributes,
|
|
5
|
-
memo,
|
|
6
|
-
ReactNode,
|
|
7
|
-
} from "react";
|
|
8
|
-
import { cx } from "../utils/classNames";
|
|
9
|
-
import { Spacer } from "./Spacer";
|
|
10
|
-
import { textStyles } from "./Text";
|
|
11
|
-
|
|
12
|
-
export const Section = forwardRef<
|
|
13
|
-
HTMLDivElement,
|
|
14
|
-
React.HTMLAttributes<HTMLDivElement>
|
|
15
|
-
>(({ className, ...props }, ref) => (
|
|
16
|
-
<div
|
|
17
|
-
ref={ref}
|
|
18
|
-
className={cx(`n-flex-none n-flex n-flex-col`, className)}
|
|
19
|
-
{...props}
|
|
20
|
-
/>
|
|
21
|
-
));
|
|
22
|
-
|
|
23
|
-
export const SectionHeader = forwardRef<
|
|
24
|
-
HTMLDivElement,
|
|
25
|
-
React.HTMLAttributes<HTMLDivElement>
|
|
26
|
-
>(({ className, ...props }, ref) => (
|
|
27
|
-
<div ref={ref} className={cx(`n-flex n-items-center`, className)} {...props} />
|
|
28
|
-
));
|
|
29
|
-
|
|
30
|
-
type TitleTextStyle = "small" | "heading5" | "heading4" | "heading3";
|
|
31
|
-
|
|
32
|
-
export const Title = forwardRef<
|
|
33
|
-
HTMLDivElement,
|
|
34
|
-
React.HTMLAttributes<HTMLDivElement> & {
|
|
35
|
-
$textStyle?: TitleTextStyle;
|
|
36
|
-
}
|
|
37
|
-
>(({ className, $textStyle, ...props }, ref) => (
|
|
38
|
-
<div
|
|
39
|
-
ref={ref}
|
|
40
|
-
className={cx(
|
|
41
|
-
`n-flex n-select-none ${
|
|
42
|
-
$textStyle
|
|
43
|
-
? `${textStyles[$textStyle]} n-text-text`
|
|
44
|
-
: "n-font-sans n-text-label n-text-text-muted n-font-semibold"
|
|
45
|
-
} `,
|
|
46
|
-
className
|
|
47
|
-
)}
|
|
48
|
-
{...props}
|
|
49
|
-
/>
|
|
50
|
-
));
|
|
51
|
-
|
|
52
|
-
export const Row = forwardRef<
|
|
53
|
-
HTMLDivElement,
|
|
54
|
-
React.HTMLAttributes<HTMLDivElement>
|
|
55
|
-
>(({ className, ...props }, ref) => (
|
|
56
|
-
<div
|
|
57
|
-
ref={ref}
|
|
58
|
-
className={cx(`n-flex-1 n-flex n-flex-row n-items-center`, className)}
|
|
59
|
-
{...props}
|
|
60
|
-
/>
|
|
61
|
-
));
|
|
62
|
-
|
|
63
|
-
export const Column = forwardRef<
|
|
64
|
-
HTMLDivElement,
|
|
65
|
-
React.HTMLAttributes<HTMLDivElement>
|
|
66
|
-
>(({ className, ...props }, ref) => (
|
|
67
|
-
<div
|
|
68
|
-
ref={ref}
|
|
69
|
-
className={cx(`n-flex-1 n-flex n-flex-col n-gap-1`, className)}
|
|
70
|
-
{...props}
|
|
71
|
-
/>
|
|
72
|
-
));
|
|
73
|
-
|
|
74
|
-
export const Checkbox = forwardRef<
|
|
75
|
-
HTMLInputElement,
|
|
76
|
-
React.InputHTMLAttributes<HTMLInputElement>
|
|
77
|
-
>(({ className, ...props }, ref) => (
|
|
78
|
-
<input
|
|
79
|
-
ref={ref}
|
|
80
|
-
type="checkbox"
|
|
81
|
-
className={cx(`n-m-0 focus:n-z-interactable`, className)}
|
|
82
|
-
{...props}
|
|
83
|
-
/>
|
|
84
|
-
));
|
|
85
|
-
|
|
86
|
-
export const Text = forwardRef<
|
|
87
|
-
HTMLSpanElement,
|
|
88
|
-
React.HTMLAttributes<HTMLSpanElement>
|
|
89
|
-
>(({ className, ...props }, ref) => (
|
|
90
|
-
<span
|
|
91
|
-
ref={ref}
|
|
92
|
-
className={cx(`n-font-sans n-text-heading5 n-font-normal`, className)}
|
|
93
|
-
{...props}
|
|
94
|
-
/>
|
|
95
|
-
));
|
|
96
|
-
|
|
97
|
-
export const VerticalSeparator = () => (
|
|
98
|
-
<Spacer.Vertical size="inspector-v-separator" />
|
|
99
|
-
);
|
|
100
|
-
|
|
101
|
-
export const HorizontalSeparator = () => (
|
|
102
|
-
<Spacer.Horizontal size="inspector-h-separator" />
|
|
103
|
-
);
|
|
104
|
-
|
|
105
|
-
// const SliderRowLabel = forwardRef<
|
|
106
|
-
// HTMLSpanElement,
|
|
107
|
-
// React.HTMLAttributes<HTMLSpanElement>
|
|
108
|
-
// >(({ className, ...props }, ref) => (
|
|
109
|
-
// <span
|
|
110
|
-
// ref={ref}
|
|
111
|
-
// className={`font-sans text-heading5 font-normal text-text-muted -mb-[6px] `, className}
|
|
112
|
-
// {...props}
|
|
113
|
-
// />
|
|
114
|
-
// ));
|
|
115
|
-
|
|
116
|
-
export const RowLabel = forwardRef(function RowLabel(
|
|
117
|
-
{
|
|
118
|
-
className,
|
|
119
|
-
$textStyle,
|
|
120
|
-
...props
|
|
121
|
-
}: LabelHTMLAttributes<HTMLLabelElement> & {
|
|
122
|
-
$textStyle?: TitleTextStyle | "label";
|
|
123
|
-
},
|
|
124
|
-
ref: ForwardedRef<HTMLLabelElement>
|
|
125
|
-
) {
|
|
126
|
-
return (
|
|
127
|
-
<label
|
|
128
|
-
ref={ref}
|
|
129
|
-
className={cx(
|
|
130
|
-
`n-font-sans n-text-label n-uppercase n-flex n-items-center n-leading-[19px] n-font-bold n-text-text-subtle n-z-label ${
|
|
131
|
-
$textStyle && textStyles[$textStyle]
|
|
132
|
-
} `,
|
|
133
|
-
className
|
|
134
|
-
)}
|
|
135
|
-
{...props}
|
|
136
|
-
/>
|
|
137
|
-
);
|
|
138
|
-
});
|
|
139
|
-
|
|
140
|
-
interface LabeledRowProps {
|
|
141
|
-
id?: string;
|
|
142
|
-
children: ReactNode;
|
|
143
|
-
label: ReactNode;
|
|
144
|
-
labelTextStyle?: TitleTextStyle;
|
|
145
|
-
right?: ReactNode;
|
|
146
|
-
className?: string;
|
|
147
|
-
}
|
|
148
|
-
|
|
149
|
-
export const LabeledRow = memo(function LabeledRow({
|
|
150
|
-
id,
|
|
151
|
-
children,
|
|
152
|
-
label,
|
|
153
|
-
labelTextStyle,
|
|
154
|
-
right,
|
|
155
|
-
className,
|
|
156
|
-
}: LabeledRowProps) {
|
|
157
|
-
return (
|
|
158
|
-
<Row id={id} className={className}>
|
|
159
|
-
<Column>
|
|
160
|
-
<RowLabel $textStyle={labelTextStyle}>
|
|
161
|
-
{label}
|
|
162
|
-
{right && <Spacer.Horizontal />}
|
|
163
|
-
{right}
|
|
164
|
-
</RowLabel>
|
|
165
|
-
<Row>{children}</Row>
|
|
166
|
-
</Column>
|
|
167
|
-
</Row>
|
|
168
|
-
);
|
|
169
|
-
});
|
|
170
|
-
|
|
171
|
-
// interface LabeledSliderRowProps {
|
|
172
|
-
// children: ReactNode;
|
|
173
|
-
// label: string;
|
|
174
|
-
// }
|
|
175
|
-
|
|
176
|
-
// export const LabeledSliderRow = memo(function LabeledSliderRow({
|
|
177
|
-
// children,
|
|
178
|
-
// label,
|
|
179
|
-
// }: LabeledSliderRowProps) {
|
|
180
|
-
// return (
|
|
181
|
-
// <Row>
|
|
182
|
-
// <Column>
|
|
183
|
-
// <SliderRowLabel>{label}</SliderRowLabel>
|
|
184
|
-
// <Row>{children}</Row>
|
|
185
|
-
// </Column>
|
|
186
|
-
// </Row>
|
|
187
|
-
// );
|
|
188
|
-
// });
|