@noya-app/noya-designsystem 0.1.64 → 0.1.65

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.
Files changed (115) hide show
  1. package/.turbo/turbo-build.log +13 -10
  2. package/CHANGELOG.md +12 -0
  3. package/dist/index.css +1 -1
  4. package/dist/index.d.mts +501 -228
  5. package/dist/index.d.ts +501 -228
  6. package/dist/index.js +6738 -2571
  7. package/dist/index.js.map +1 -1
  8. package/dist/index.mjs +6697 -2499
  9. package/dist/index.mjs.map +1 -1
  10. package/package.json +6 -6
  11. package/src/components/ActivityIndicator.tsx +9 -4
  12. package/src/components/ActivityLog.tsx +197 -0
  13. package/src/components/AnimatePresence.tsx +37 -22
  14. package/src/components/Avatar.tsx +42 -25
  15. package/src/components/Banner.tsx +57 -11
  16. package/src/components/BaseToolbar.tsx +29 -7
  17. package/src/components/Breadcrumbs.tsx +2 -2
  18. package/src/components/Button.tsx +23 -24
  19. package/src/components/Checkbox.tsx +6 -35
  20. package/src/components/Chip.tsx +45 -33
  21. package/src/components/Collection.tsx +16 -11
  22. package/src/components/ColorSwatch.tsx +3 -3
  23. package/src/components/ColorSwatchControl.tsx +2 -2
  24. package/src/components/Combobox.tsx +6 -6
  25. package/src/components/ComboboxMenu.tsx +6 -5
  26. package/src/components/CommandPalette.tsx +1 -1
  27. package/src/components/Dialog.tsx +6 -12
  28. package/src/components/Divider.tsx +8 -8
  29. package/src/components/DraggableMenuButton.tsx +9 -5
  30. package/src/components/Drawer.tsx +5 -5
  31. package/src/components/DropdownMenu.tsx +1 -1
  32. package/src/components/EditableText.tsx +2 -2
  33. package/src/components/Fade.tsx +13 -13
  34. package/src/components/FileUploadIndicator.tsx +11 -11
  35. package/src/components/FloatingWindow.tsx +2 -2
  36. package/src/components/Grid.tsx +18 -11
  37. package/src/components/GridView.tsx +32 -25
  38. package/src/components/IVirtualizedList.tsx +5 -0
  39. package/src/components/Icons.tsx +24 -4
  40. package/src/components/InputField.tsx +19 -19
  41. package/src/components/InspectorContainer.tsx +2 -2
  42. package/src/components/InspectorPrimitives.tsx +15 -9
  43. package/src/components/Label.tsx +4 -3
  44. package/src/components/LabeledElementView.tsx +3 -3
  45. package/src/components/LabeledField.tsx +6 -6
  46. package/src/components/List.tsx +103 -45
  47. package/src/components/ListMenu.tsx +91 -0
  48. package/src/components/ListNavigator.tsx +106 -0
  49. package/src/components/ListView.tsx +20 -1158
  50. package/src/components/MediaThumbnail.tsx +56 -15
  51. package/src/components/Message.tsx +5 -5
  52. package/src/components/Navigator.tsx +461 -0
  53. package/src/components/NoyaLogo.tsx +1 -1
  54. package/src/components/Popover.tsx +9 -5
  55. package/src/components/Progress.tsx +19 -9
  56. package/src/components/ResizableContainer.tsx +187 -0
  57. package/src/components/RingProgress.tsx +128 -0
  58. package/src/components/ScrollArea.tsx +4 -4
  59. package/src/components/ScrollableSidebar.tsx +10 -0
  60. package/src/components/SearchCompletionMenu.tsx +3 -3
  61. package/src/components/Section.tsx +107 -57
  62. package/src/components/SegmentedControl.tsx +29 -29
  63. package/src/components/SelectMenu.tsx +13 -20
  64. package/src/components/SelectionToolbar.tsx +4 -3
  65. package/src/components/Slider.tsx +9 -9
  66. package/src/components/Spacer.tsx +2 -2
  67. package/src/components/StackNavigator.tsx +378 -0
  68. package/src/components/Stepper.tsx +88 -0
  69. package/src/components/Switch.tsx +4 -4
  70. package/src/components/Tabs.tsx +3 -3
  71. package/src/components/Text.tsx +23 -13
  72. package/src/components/TextArea.tsx +3 -3
  73. package/src/components/Toast.tsx +4 -4
  74. package/src/components/Toolbar.tsx +50 -9
  75. package/src/components/ToolbarDrawer.tsx +2 -2
  76. package/src/components/Tooltip.tsx +1 -1
  77. package/src/components/TreeView.tsx +11 -4
  78. package/src/components/UserPointer.tsx +4 -4
  79. package/src/components/ai-assistant/AIAssistantLayout.tsx +8 -8
  80. package/src/components/blocks/ImageBlockComponent.tsx +13 -7
  81. package/src/components/connected-users-menu/ConnectedUsersMenuLayout.tsx +4 -4
  82. package/src/components/file-explorer/FileExplorerLayout.tsx +20 -8
  83. package/src/components/internal/Checkmark.tsx +1 -1
  84. package/src/components/internal/Menu.tsx +22 -18
  85. package/src/components/internal/MenuViewport.tsx +13 -6
  86. package/src/components/internal/SelectItem.tsx +3 -3
  87. package/src/components/internal/TextInput.tsx +5 -1
  88. package/src/components/listView/ListViewContexts.tsx +68 -0
  89. package/src/components/listView/ListViewEditableRowTitle.tsx +55 -0
  90. package/src/components/listView/ListViewRoot.tsx +521 -0
  91. package/src/components/listView/ListViewRow.tsx +475 -0
  92. package/src/components/listView/ListViewRowTitle.tsx +21 -0
  93. package/src/components/listView/types.ts +11 -0
  94. package/src/components/pipeline/PipelineResultLayout.tsx +6 -6
  95. package/src/components/sorting/DragRegistration.tsx +2 -1
  96. package/src/components/sorting/SharedDragProvider.tsx +91 -9
  97. package/src/components/sorting/Sortable.tsx +71 -17
  98. package/src/components/workspace/DrawerWorkspaceLayout.tsx +5 -5
  99. package/src/components/workspace/PanelWorkspaceLayout.tsx +65 -49
  100. package/src/components/workspace/VerticalTabMenu.tsx +25 -15
  101. package/src/components/workspace/WorkspaceLayout.tsx +30 -21
  102. package/src/contexts/DialogContext.tsx +17 -5
  103. package/src/hooks/useIndent.ts +3 -8
  104. package/src/index.css +24 -10
  105. package/src/index.tsx +10 -5
  106. package/src/utils/classNames.ts +52 -6
  107. package/src/utils/editableBlockStyles.ts +2 -2
  108. package/src/utils/formatByteSize.ts +1 -0
  109. package/src/utils/inputs.ts +8 -6
  110. package/src/utils/sketchColor.ts +0 -34
  111. package/tailwind.config.ts +1 -0
  112. package/src/components/FillInputField.tsx +0 -37
  113. package/src/components/FillPreviewBackground.tsx +0 -134
  114. package/src/components/GradientPicker.tsx +0 -90
  115. package/src/utils/getGradientBackground.tsx +0 -31
@@ -20,12 +20,12 @@ export const Divider = memo(function Divider({
20
20
  return (
21
21
  <div
22
22
  className={cx(
23
- `h-px min-h-px self-stretch`,
23
+ `n-h-px n-min-h-px n-self-stretch`,
24
24
  variant === "strong"
25
- ? "bg-divider-strong"
25
+ ? "n-bg-divider-strong"
26
26
  : variant === "subtle"
27
- ? "bg-divider-subtle"
28
- : "bg-divider",
27
+ ? "n-bg-divider-subtle"
28
+ : "n-bg-divider",
29
29
  className
30
30
  )}
31
31
  style={{
@@ -50,12 +50,12 @@ export const DividerVertical = memo(function DividerVertical({
50
50
  return (
51
51
  <div
52
52
  className={cx(
53
- `w-px min-w-px self-stretch`,
53
+ `n-w-px n-min-w-px n-self-stretch`,
54
54
  variant === "strong"
55
- ? "bg-divider-strong"
55
+ ? "n-bg-divider-strong"
56
56
  : variant === "subtle"
57
- ? "bg-divider-subtle"
58
- : "bg-divider",
57
+ ? "n-bg-divider-subtle"
58
+ : "n-bg-divider",
59
59
  className
60
60
  )}
61
61
  style={{
@@ -1,6 +1,5 @@
1
1
  "use client";
2
2
 
3
- import { DragHandleDots2Icon } from "@noya-app/noya-icons";
4
3
  import {
5
4
  memoGeneric,
6
5
  useControlledOrUncontrolled,
@@ -9,6 +8,7 @@ import React, { useCallback, useState } from "react";
9
8
  import { cssVars } from "../theme";
10
9
  import { cx } from "../utils/classNames";
11
10
  import { DropdownMenu } from "./DropdownMenu";
11
+ import { Icon, IconName } from "./Icons";
12
12
  import { MenuItem } from "./internal/Menu";
13
13
 
14
14
  /**
@@ -25,6 +25,7 @@ export const DraggableMenuButton = memoGeneric(function DraggableMenuButton<
25
25
  isVisible = true,
26
26
  className,
27
27
  style,
28
+ iconName = "DragHandleDots2Icon",
28
29
  ...rest
29
30
  }: {
30
31
  open?: boolean;
@@ -35,6 +36,7 @@ export const DraggableMenuButton = memoGeneric(function DraggableMenuButton<
35
36
  isVisible?: boolean;
36
37
  className?: string;
37
38
  style?: React.CSSProperties;
39
+ iconName?: IconName;
38
40
  } & Omit<
39
41
  React.DetailedHTMLProps<React.HTMLAttributes<HTMLDivElement>, HTMLDivElement>,
40
42
  "onSelect"
@@ -95,7 +97,7 @@ export const DraggableMenuButton = memoGeneric(function DraggableMenuButton<
95
97
  <div
96
98
  {...rest}
97
99
  className={cx(
98
- "cursor-pointer rounded flex items-center justify-center py-[2px] hover:bg-input-background-light active:bg-active-background ",
100
+ "n-cursor-pointer n-rounded n-flex n-items-center n-justify-center n-py-[2px] hover:n-bg-input-background-light active:n-bg-active-background",
99
101
  className
100
102
  )}
101
103
  style={style}
@@ -115,14 +117,16 @@ export const DraggableMenuButton = memoGeneric(function DraggableMenuButton<
115
117
  onSelect={onSelect}
116
118
  shouldBindKeyboardShortcuts={false}
117
119
  >
118
- <div className="pointer-events-none h-[15px]">
119
- <DragHandleDots2Icon
120
+ <div className="n-pointer-events-none n-h-[15px]">
121
+ <Icon
122
+ name={iconName}
120
123
  color={isVisible || open ? cssVars.colors.icon : "transparent"}
121
124
  />
122
125
  </div>
123
126
  </DropdownMenu>
124
127
  ) : (
125
- <DragHandleDots2Icon
128
+ <Icon
129
+ name={iconName}
126
130
  color={isVisible || open ? cssVars.colors.icon : "transparent"}
127
131
  />
128
132
  )}
@@ -66,8 +66,8 @@ export const Drawer = React.memo(
66
66
  <>
67
67
  <Dialog.Overlay
68
68
  className={cx(
69
- "inset-0 bg-black/50",
70
- positioning === "absolute" ? "absolute" : "fixed",
69
+ "n-inset-0 n-bg-black/50",
70
+ positioning === "absolute" ? "n-absolute" : "n-fixed",
71
71
  overlayClassName
72
72
  )}
73
73
  style={overlayStyle}
@@ -76,9 +76,9 @@ export const Drawer = React.memo(
76
76
  id={id}
77
77
  style={style}
78
78
  className={cx(
79
- `top-0 bottom-0 z-50 overflow-y-auto bg-sidebar-background rounded-none max-h-none max-w-none sm:!max-w-sm w-full border-divider-strong`,
80
- positioning === "absolute" ? "absolute" : "fixed",
81
- side === "left" ? "left-0 border-r" : "right-0 border-l",
79
+ `n-top-0 n-bottom-0 n-z-50 n-overflow-y-auto n-bg-sidebar-background n-rounded-none n-max-h-none n-max-w-none sm:!n-max-w-sm n-w-full n-border-divider-strong`,
80
+ positioning === "absolute" ? "n-absolute" : "n-fixed",
81
+ side === "left" ? "n-left-0 n-border-r" : "n-right-0 n-border-l",
82
82
  className
83
83
  )}
84
84
  >
@@ -18,7 +18,7 @@ import {
18
18
  portalScopeProps,
19
19
  usePortalScopeId,
20
20
  } from "../contexts/PortalScopeContext";
21
- import Button, { ButtonProps } from "./Button";
21
+ import { Button, ButtonProps } from "./Button";
22
22
  import { MenuProps } from "./ContextMenu";
23
23
  import { getKeyboardShortcutsForMenuItems, styles } from "./internal/Menu";
24
24
  import { MenuViewport } from "./internal/MenuViewport";
@@ -151,7 +151,7 @@ export const EditableText = memo(
151
151
  });
152
152
 
153
153
  const input = (
154
- <div className="flex absolute inset-0 -mx-1.5 -my-1">
154
+ <div className="n-flex n-absolute n-inset-0 -mx-1.5 -n-my-1">
155
155
  <InputField.Root onFocusChange={setFocused}>
156
156
  <InputField.Input
157
157
  ref={inputRef}
@@ -198,7 +198,7 @@ export const EditableText = memo(
198
198
  );
199
199
 
200
200
  return (
201
- <div className={cx("flex relative", className)} style={style}>
201
+ <div className={cx("n-flex n-relative", className)} style={style}>
202
202
  {preview}
203
203
  {focused && !readOnly && input}
204
204
  </div>
@@ -27,29 +27,29 @@ export const Fade = ({
27
27
  position = "front",
28
28
  }: FadeProps) => {
29
29
  const gradientDirection = {
30
- left: "to-l",
31
- right: "to-r",
32
- top: "to-t",
33
- bottom: "to-b",
30
+ left: "n-bg-gradient-to-l",
31
+ right: "n-bg-gradient-to-r",
32
+ top: "n-bg-gradient-to-t",
33
+ bottom: "n-bg-gradient-to-b",
34
34
  }[direction];
35
35
 
36
36
  const positionClasses = {
37
- left: "left-0 top-0 bottom-0",
38
- right: "right-0 top-0 bottom-0",
39
- top: "left-0 right-0 top-0",
40
- bottom: "left-0 right-0 bottom-0",
37
+ left: "n-left-0 n-top-0 n-bottom-0",
38
+ right: "n-right-0 n-top-0 n-bottom-0",
39
+ top: "n-left-0 n-right-0 n-top-0",
40
+ bottom: "n-left-0 n-right-0 n-bottom-0",
41
41
  }[direction];
42
42
 
43
43
  return (
44
- <div className={cx("relative", className)} style={{ height }}>
44
+ <div className={cx("n-relative", className)} style={{ height }}>
45
45
  {position === "front" ? children : null}
46
46
  <div
47
47
  className={cx(
48
- "absolute pointer-events-none",
48
+ "n-absolute n-pointer-events-none",
49
49
  positionClasses,
50
- `bg-gradient-${gradientDirection}`,
51
- "from-transparent to-background",
52
- zIndex && `z-[${zIndex}]`
50
+ gradientDirection,
51
+ "n-from-transparent n-to-background",
52
+ zIndex && `n-z-[${zIndex}]`
53
53
  )}
54
54
  style={{
55
55
  width: width ?? "100%",
@@ -24,24 +24,24 @@ export function FileUploadIndicator({
24
24
  const value = typeof percent === "number" ? Math.round(percent) : 0;
25
25
 
26
26
  return (
27
- <div className="flex items-center gap-2">
28
- <div className="w-12 h-12 bg-background rounded-md overflow-hidden">
27
+ <div className="n-flex n-items-center n-gap-2">
28
+ <div className="n-w-12 n-h-12 n-bg-background n-rounded-md n-overflow-hidden">
29
29
  <MediaThumbnail
30
30
  size="medium"
31
31
  fileName={name}
32
32
  contentType={contentType}
33
33
  />
34
34
  </div>
35
- <div className="flex flex-col flex-1 justify-center gap-1 min-w-0">
35
+ <div className="n-flex n-flex-col n-flex-1 n-justify-center n-gap-1 n-min-w-0">
36
36
  {name && (
37
- <Small color="text" className="truncate leading-none">
37
+ <Small color="text" className="n-truncate n-leading-none">
38
38
  {name}
39
39
  </Small>
40
40
  )}
41
41
  {typeof total === "number" && typeof percent === "number" && (
42
42
  <Small
43
43
  color="textSubtle"
44
- className="leading-none"
44
+ className="n-leading-none"
45
45
  style={{ fontSize: "11px" }}
46
46
  >
47
47
  {formatByteSize(Math.round((percent / 100) * total))} /{" "}
@@ -52,23 +52,23 @@ export function FileUploadIndicator({
52
52
  <Progress
53
53
  value={value}
54
54
  style={{ marginTop: "3px", height: "3px" }}
55
- className="rounded-sm"
55
+ className="n-rounded-sm"
56
56
  colorScheme="secondary"
57
57
  />
58
58
  )}
59
59
  </div>
60
- <div className="flex items-center justify-center gap-2">
60
+ <div className="n-flex n-items-center n-justify-center n-gap-2">
61
61
  {typeof value === "number" && (
62
62
  <Small
63
63
  color="textSubtle"
64
64
  style={{ lineHeight: "1", fontSize: "13px" }}
65
- className="tabular-nums text-right w-10"
65
+ className="n-tabular-nums n-text-right n-w-10"
66
66
  >
67
67
  {value}%
68
68
  </Small>
69
69
  )}
70
70
  {done ? (
71
- <div className="w-[15px] h-[15px] bg-secondary rounded-full flex items-center justify-center text-white">
71
+ <div className="n-w-[15px] n-h-[15px] n-bg-secondary n-rounded-full n-flex n-items-center n-justify-center n-text-white">
72
72
  <Checkmark />
73
73
  </div>
74
74
  ) : (
@@ -86,13 +86,13 @@ export function FileUploadList({
86
86
  }) {
87
87
  return (
88
88
  <>
89
- <div className="flex items-center gap-2 py-2 px-4">
89
+ <div className="n-flex n-items-center n-gap-2 n-py-2 n-px-4">
90
90
  <Heading5>
91
91
  Uploading {uploads.length} {uploads.length === 1 ? "asset" : "assets"}
92
92
  </Heading5>
93
93
  </div>
94
94
  <Divider />
95
- <div className="flex flex-col gap-3 max-h-[500px] overflow-y-auto overflow-x-hidden py-4 px-4">
95
+ <div className="n-flex n-flex-col n-gap-3 n-max-h-[500px] n-overflow-y-auto n-overflow-x-hidden n-py-4 n-px-4">
96
96
  {uploads.map((upload) => (
97
97
  <FileUploadIndicator
98
98
  key={upload.id}
@@ -127,11 +127,11 @@ function defaultRenderToolbar({
127
127
  }) {
128
128
  return (
129
129
  <>
130
- <Small className="flex-1 font-medium text-text">{title}</Small>
130
+ <Small className="n-flex-1 n-font-medium n-text-text">{title}</Small>
131
131
  {toolbarContent}
132
132
  <IconButton
133
133
  iconName="Cross3Icon"
134
- className="h-8 w-8 rounded-full"
134
+ className="n-h-8 n-w-8 n-rounded-full"
135
135
  onClick={onClose}
136
136
  size={20}
137
137
  style={{
@@ -84,6 +84,7 @@ export const Grid = memoGeneric(
84
84
  renderThumbnail,
85
85
  renderAction,
86
86
  renderDetail,
87
+ renderRight,
87
88
  onSelectionChange,
88
89
  selectedIds = emptyArray,
89
90
  // itemRoleDescription = "clickable item",
@@ -159,10 +160,10 @@ export const Grid = memoGeneric(
159
160
  aria-multiselectable={true}
160
161
  minColumnWidth={minColumnWidth}
161
162
  scrollable={items.length > 0 && scrollable}
162
- contentClassName={cx(items.length === 0 && "flex flex-1")}
163
+ contentClassName={cx(items.length === 0 && "n-flex n-flex-1")}
163
164
  gap={gap}
164
165
  className={cx(
165
- isDropTargetActive && "bg-selected-list-item-background",
166
+ isDropTargetActive && "n-bg-selected-list-item-background",
166
167
  className
167
168
  )}
168
169
  {...dropTargetProps}
@@ -212,12 +213,14 @@ export const Grid = memoGeneric(
212
213
 
213
214
  const subtitle = (
214
215
  <span
215
- className={cx(isSelected && "text-selected-list-item-text")}
216
+ className={cx(isSelected && "n-text-selected-list-item-text")}
216
217
  >
217
218
  {renderDetail?.(item, isSelected)}
218
219
  </span>
219
220
  );
220
221
 
222
+ const right = renderRight?.(item, isSelected);
223
+
221
224
  return (
222
225
  <GridView.Item<M>
223
226
  key={id}
@@ -232,9 +235,12 @@ export const Grid = memoGeneric(
232
235
  setHoveredId(isHovering ? id : undefined);
233
236
  }}
234
237
  title={
235
- <div className="flex items-center gap-2 flex-row">
238
+ <div className="n-flex n-items-center n-gap-2 n-flex-row">
236
239
  <EditableText
237
- className={cx(detailPosition === "end" && "flex-1")}
240
+ className={cx(
241
+ (detailPosition === "end" || right) && "n-flex-1",
242
+ "n-truncate n-select-none"
243
+ )}
238
244
  tabIndex={isRenaming ? undefined : -1}
239
245
  value={getName(item)}
240
246
  focused={isRenaming}
@@ -248,20 +254,21 @@ export const Grid = memoGeneric(
248
254
  setRenamingId(undefined);
249
255
  }}
250
256
  // max height ensures preview text and input are one line
251
- textClassName="bg-listview-editing-background max-h-input-height"
257
+ textClassName="n-bg-listview-editing-background n-max-h-input-height"
252
258
  >
253
259
  {(props) => (
254
260
  <span
255
261
  {...props}
256
262
  className={cx(
257
263
  isSelected
258
- ? "text-selected-list-item-text"
259
- : "text-text",
260
- "truncate select-none"
264
+ ? "n-text-selected-list-item-text"
265
+ : "n-text-text",
266
+ "n-truncate n-select-none"
261
267
  )}
262
268
  />
263
269
  )}
264
270
  </EditableText>
271
+ {right && <div className="n-flex-none">{right}</div>}
265
272
  {detailPosition === "end" && subtitle}
266
273
  </div>
267
274
  }
@@ -295,8 +302,8 @@ export const Grid = memoGeneric(
295
302
  {thumbnail && (
296
303
  <div
297
304
  className={cx(
298
- "rounded overflow-hidden flex-none flex w-full",
299
- isSelected && "text-selected-list-item-text"
305
+ "n-rounded n-overflow-hidden n-flex-none n-flex n-w-full",
306
+ isSelected && "n-text-selected-list-item-text"
300
307
  )}
301
308
  tabIndex={-1}
302
309
  >
@@ -34,9 +34,9 @@ const ItemTitle = ({
34
34
  return (
35
35
  <span
36
36
  className={cx(
37
- "font-sans text-heading5 text-text-muted font-medium",
37
+ "n-font-sans n-text-heading5 n-text-text-muted n-font-medium",
38
38
  showBackground &&
39
- "bg-sidebar-background border border-divider-subtle rounded-[2px] backdrop-blur-[4px] p-[2px_4px]"
39
+ "n-bg-sidebar-background n-n-border n-border-divider-subtle n-rounded-[2px] n-backdrop-blur-[4px] n-p-[2px_4px]"
40
40
  )}
41
41
  >
42
42
  {children}
@@ -54,9 +54,9 @@ const ItemDescription = ({
54
54
  return (
55
55
  <span
56
56
  className={cx(
57
- "font-sans text-sm text-text-muted select-none truncate",
57
+ "n-font-sans n-text-sm n-text-text-muted n-select-none n-truncate",
58
58
  showBackground &&
59
- "bg-sidebar-background border border-divider-subtle rounded-[2px] backdrop-blur-[4px] p-[2px_4px]"
59
+ "n-bg-sidebar-background n-n-border n-border-divider-subtle n-rounded-[2px] n-backdrop-blur-[4px] n-p-[2px_4px]"
60
60
  )}
61
61
  >
62
62
  {children}
@@ -73,7 +73,10 @@ const SectionTitle = ({
73
73
  }) => {
74
74
  return (
75
75
  <span
76
- className={`font-sans text-heading3 font-medium user-select-none truncate ${last ? "text-text" : "text-text-muted"}`}
76
+ className={cx(
77
+ "n-font-sans n-text-heading3 n-font-medium n-user-select-none n-truncate",
78
+ last ? "n-text-text" : "n-text-text-muted"
79
+ )}
77
80
  >
78
81
  {children}
79
82
  </span>
@@ -88,7 +91,7 @@ interface ItemProps<MenuItemType extends string = string> {
88
91
  loading?: boolean;
89
92
  selected?: boolean;
90
93
  onClick?: (event: React.MouseEvent) => void;
91
- onSelect?: (options: KeyModifiers) => void;
94
+ onSelect?: (options: KeyModifiers & { stopPropagation(): void }) => void;
92
95
  onDoubleClick?: () => void;
93
96
  onHoverChange?: (isHovering: boolean) => void;
94
97
  children?: ReactNode;
@@ -175,14 +178,14 @@ const GridViewItem = forwardRefGeneric(function GridViewItem<
175
178
  <Component
176
179
  {...props}
177
180
  className={cx(
178
- "flex flex-col relative rounded p-2 -m-2 text-text",
179
- "cursor-pointer",
180
- "active:opacity-70",
181
- selected && "bg-selected-list-item-background",
182
- hovered && "bg-list-view-hover-background",
183
- disabled && "opacity-50",
184
- showInsideDropIndicator && "ring-2 ring-primary ring-inset",
185
- "focus:ring-2 focus:ring-primary focus:ring-inset focus:outline-none"
181
+ "n-flex n-flex-col n-relative n-rounded n-p-2 -n-m-2 n-text-text",
182
+ "n-cursor-pointer",
183
+ "active:n-opacity-70",
184
+ selected && "n-bg-selected-list-item-background",
185
+ hovered && "n-bg-list-view-hover-background",
186
+ disabled && "n-opacity-50",
187
+ showInsideDropIndicator && "n-ring-2 n-ring-primary n-ring-inset",
188
+ "focus:n-ring-2 focus:n-ring-primary focus:n-ring-inset focus:n-outline-none"
186
189
  )}
187
190
  id={id}
188
191
  href={href}
@@ -196,8 +199,10 @@ const GridViewItem = forwardRefGeneric(function GridViewItem<
196
199
  >
197
200
  <div
198
201
  className={cx(
199
- "flex items-center justify-center rounded",
200
- bordered ? "border border-divider" : "border border-transparent"
202
+ "n-flex n-items-center n-justify-center n-rounded",
203
+ bordered
204
+ ? "n-border n-border-divider"
205
+ : "n-border n-border-transparent"
201
206
  )}
202
207
  style={style}
203
208
  >
@@ -216,7 +221,7 @@ const GridViewItem = forwardRefGeneric(function GridViewItem<
216
221
  </>
217
222
  )}
218
223
  {textPosition === "overlay" && hovered && (title || subtitle) && (
219
- <div className="absolute inset-0 flex flex-col justify-end items-start p-1 pointer-events-none truncate gap-0.5">
224
+ <div className="n-absolute n-inset-0 n-flex n-flex-col n-justify-end n-items-start n-p-1 n-pointer-events-none n-truncate n-gap-0.5">
220
225
  {title && <ItemTitle showBackground>{title}</ItemTitle>}
221
226
  {subtitle && (
222
227
  <ItemDescription showBackground>{subtitle}</ItemDescription>
@@ -224,12 +229,12 @@ const GridViewItem = forwardRefGeneric(function GridViewItem<
224
229
  </div>
225
230
  )}
226
231
  {action && (
227
- <div className="absolute top-[7px] right-[7px] flex flex-col justify-end items-start p-1 truncate gap-0.5">
232
+ <div className="n-absolute n-top-[7px] n-right-[7px] n-flex n-flex-col n-justify-end n-items-start n-p-1 n-truncate n-gap-0.5">
228
233
  {action}
229
234
  </div>
230
235
  )}
231
236
  {loading && (
232
- <div className="flex flex-col justify-start items-end p-1 pointer-events-none animate-shimmer absolute inset-0 bg-gradient-to-r from-white/0 via-[rgb(226,232,240)]/50 to-white/0 bg-length:200%_100%]">
237
+ <div className="n-flex n-flex-col n-justify-start n-items-end n-p-1 n-pointer-events-none n-animate-shimmer n-absolute n-inset-0 n-bg-gradient-to-r n-from-white/0 n-via-[rgb(226,232,240)]/50 n-to-white/0 n-bg-[length:200%_100%]">
233
238
  <ActivityIndicator opacity={0.5} size={13} />
234
239
  </div>
235
240
  )}
@@ -252,7 +257,7 @@ const GridViewItem = forwardRefGeneric(function GridViewItem<
252
257
  element = (
253
258
  <Tooltip
254
259
  content={
255
- <div className="flex flex-col gap-0.5">
260
+ <div className="n-flex n-flex-col gap-0.5">
256
261
  <ItemTitle>{title}</ItemTitle>
257
262
  <ItemDescription>{subtitle}</ItemDescription>
258
263
  </div>
@@ -340,8 +345,8 @@ const GridViewRoot = forwardRef(function GridViewRoot(
340
345
 
341
346
  const mergedClassName = useMemo(() => {
342
347
  const baseClassName = cx(
343
- "flex flex-col -mx-3",
344
- scrollable ? "basis-0 min-h-0" : "flex-none",
348
+ "n-flex n-flex-col n--mx-3",
349
+ scrollable ? "n-basis-0 n-min-h-0" : "n-flex-none",
345
350
  className
346
351
  );
347
352
 
@@ -350,7 +355,9 @@ const GridViewRoot = forwardRef(function GridViewRoot(
350
355
  });
351
356
  }, [className, scrollable]);
352
357
 
353
- const content = <div className={cx("p-3", contentClassName)}>{children}</div>;
358
+ const content = (
359
+ <div className={cx("n-p-3", contentClassName)}>{children}</div>
360
+ );
354
361
 
355
362
  return (
356
363
  <GridViewContext.Provider value={contextValue}>
@@ -389,7 +396,7 @@ function GridViewSection({
389
396
  ) : (
390
397
  <div
391
398
  role="presentation"
392
- className={cx("grid text-text", className)}
399
+ className={cx("n-grid n-text-text", className)}
393
400
  style={styles}
394
401
  >
395
402
  {children}
@@ -401,7 +408,7 @@ function GridViewSectionHeader({ title }: { title: string }) {
401
408
  const grouped = title.split("/");
402
409
 
403
410
  return (
404
- <div className="px-5">
411
+ <div className="n-px-5">
405
412
  <Spacer.Vertical size={24} />
406
413
  {withSeparatorElements(
407
414
  grouped.map((title, index) => (
@@ -0,0 +1,5 @@
1
+ "use client";
2
+
3
+ export interface IVirtualizedList {
4
+ scrollToIndex(index: number): void;
5
+ }
@@ -1,18 +1,38 @@
1
1
  import * as Icons from "@noya-app/noya-icons";
2
+ import { IconProps } from "@noya-app/noya-icons";
2
3
  import * as React from "react";
3
4
 
4
5
  export type IconName = keyof typeof Icons;
5
6
 
6
7
  export { Icons };
7
8
 
8
- export function renderIcon(
9
- iconName: Exclude<React.ReactNode, string> | IconName
10
- ): React.ReactNode {
9
+ export type IconProp = Exclude<React.ReactNode, string> | IconName;
10
+
11
+ export function renderIcon(iconName: IconProp): React.ReactNode {
11
12
  if (typeof iconName === "string") {
12
13
  const Icon = Icons[iconName as IconName];
13
14
 
14
- return <Icon className="min-h-[15px]" />;
15
+ return <Icon className="n-min-h-[15px]" />;
15
16
  }
16
17
 
17
18
  return iconName;
18
19
  }
20
+
21
+ const didWarn = new Set<string>();
22
+
23
+ export function Icon({
24
+ name,
25
+ ...props
26
+ }: { name: IconName } & Omit<IconProps, "name">) {
27
+ const Icon = Icons[name];
28
+
29
+ if (!Icon) {
30
+ if (!didWarn.has(name)) {
31
+ console.warn(`Icon ${name} not found in @noya-app/noya-icons`);
32
+ didWarn.add(name);
33
+ }
34
+ return null;
35
+ }
36
+
37
+ return <Icon {...props} />;
38
+ }
@@ -164,7 +164,7 @@ const InputFieldButton = memo(
164
164
  size={size === "medium" ? "normal" : size}
165
165
  className={cx(
166
166
  className,
167
- variant === "floating" && "bg-transparent shadow-none"
167
+ variant === "floating" && "n-bg-transparent n-shadow-none"
168
168
  )}
169
169
  {...rest}
170
170
  >
@@ -228,21 +228,21 @@ const InputElement = forwardRef(
228
228
  });
229
229
 
230
230
  const inputClassName = cx(
231
- "flex w-0 flex-1 relative border-0 outline-none min-w-0 self-stretch rounded bg-input-background focus:ring-2 focus:ring-primary placeholder:text-text-disabled transition-all",
231
+ "n-flex n-w-0 n-flex-1 n-relative n-border-0 n-outline-none n-min-w-0 n-self-stretch n-rounded n-bg-input-background focus:n-ring-2 focus:n-ring-primary placeholder:n-text-text-disabled n-transition-[box-shadow]",
232
232
  readOnly
233
- ? "text-text-muted"
233
+ ? "n-text-text-muted"
234
234
  : disabled
235
- ? "text-text-disabled"
236
- : "text-text",
237
- "font-sans font-normal",
238
- $textAlign && `text-${$textAlign}`,
235
+ ? "n-text-text-disabled"
236
+ : "n-text-text",
237
+ "n-font-sans n-font-normal",
238
+ $textAlign && `n-text-${$textAlign}`,
239
239
  size === "small"
240
- ? "text-[11px] leading-[19px] py-[1px]"
240
+ ? "n-text-[11px] n-leading-[19px] n-py-[1px]"
241
241
  : size === "large"
242
- ? "py-2.5 text-heading5"
242
+ ? "n-py-2.5 n-text-heading5"
243
243
  : size === "medium"
244
- ? "py-1 text-heading5"
245
- : $variant === "bare" && "py-1 -m-1",
244
+ ? "n-py-1 n-text-heading5"
245
+ : $variant === "bare" && "n-py-1 -n-m-1",
246
246
  className
247
247
  );
248
248
 
@@ -477,7 +477,7 @@ const RootContainer = forwardRef<
477
477
  >(({ $width, className, ...props }, ref) => (
478
478
  <div
479
479
  ref={ref}
480
- className={cx("flex flex-row relative flex-1", className)}
480
+ className={cx("n-flex n-flex-row n-relative n-flex-1", className)}
481
481
  style={{
482
482
  maxWidth: $width || $width === 0 ? `${$width}px` : undefined,
483
483
  ...props.style,
@@ -572,7 +572,7 @@ function InputFieldRoot({
572
572
 
573
573
  const insetLabel = useMemo(
574
574
  () => (
575
- <Label htmlFor={id} className="!text-text-disabled">
575
+ <Label htmlFor={id} className="!n-text-text-disabled">
576
576
  {labelProp ?? label}
577
577
  </Label>
578
578
  ),
@@ -590,7 +590,7 @@ function InputFieldRoot({
590
590
  {(end || label) && (
591
591
  <span
592
592
  ref={endRef}
593
- className={cx(endStyles, label && end && "gap-1.5", endClassName)}
593
+ className={cx(endStyles, label && end && "n-gap-1.5", endClassName)}
594
594
  >
595
595
  {labelProp
596
596
  ? insetLabel
@@ -626,7 +626,7 @@ function InputFieldRoot({
626
626
  >
627
627
  {measuredWidthObject && (
628
628
  <div
629
- className="flex flex-col overflow-hidden"
629
+ className="n-flex n-flex-col n-overflow-hidden"
630
630
  style={measuredWidthObject}
631
631
  >
632
632
  {renderPopoverContent(measuredWidthObject)}
@@ -667,12 +667,12 @@ const PrimitiveInputField = ({
667
667
  style={memoizedStyles}
668
668
  id={id}
669
669
  className={cx(
670
- "flex w-0 flex-1 relative border-none outline-none min-w-0 self-stretch rounded py-1 bg-input-background select-all pointer-events-[all] focus:ring-2 focus:ring-primary font-sans font-normal text-heading5 placeholder:text-text-disabled focus:z-interactable transition-all",
670
+ "n-flex n-w-0 n-flex-1 n-relative n-border-none n-outline-none n-min-w-0 n-self-stretch n-rounded n-py-1 n-bg-input-background n-select-all n-pointer-events-[all] focus:n-ring-2 focus:n-ring-primary n-font-sans n-font-normal n-text-heading5 placeholder:n-text-text-disabled focus:n-z-interactable n-transition-[box-shadow]",
671
671
  readOnly
672
- ? "text-text-muted"
672
+ ? "n-text-text-muted"
673
673
  : disabled
674
- ? "text-text-disabled"
675
- : "text-text",
674
+ ? "n-text-text-disabled"
675
+ : "n-text-text",
676
676
  className
677
677
  )}
678
678
  {...props}