@nikala-ui/core 0.11.0 → 0.12.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.
Files changed (107) hide show
  1. package/package.json +43 -2
  2. package/registry/api-table.json +21 -0
  3. package/registry/banner.json +1 -1
  4. package/registry/button.json +1 -1
  5. package/registry/callout.json +19 -0
  6. package/registry/checkbox.json +4 -1
  7. package/registry/code-block.json +26 -0
  8. package/registry/code-group.json +20 -0
  9. package/registry/combobox.json +1 -1
  10. package/registry/command.json +3 -2
  11. package/registry/component-viewer.json +25 -0
  12. package/registry/container.json +18 -0
  13. package/registry/context-menu.json +1 -1
  14. package/registry/create-app-updater.json +13 -0
  15. package/registry/create-document-tabs.json +13 -0
  16. package/registry/create-global-shortcut.json +13 -0
  17. package/registry/create-tauri-window.json +13 -0
  18. package/registry/create-tiptap-editor.json +34 -0
  19. package/registry/dialog.json +1 -1
  20. package/registry/dropdown-menu.json +3 -2
  21. package/registry/field.json +1 -1
  22. package/registry/file-tree.json +21 -0
  23. package/registry/footer.json +1 -1
  24. package/registry/form-message.json +3 -2
  25. package/registry/icon-button.json +1 -1
  26. package/registry/index.json +336 -5
  27. package/registry/navbar.json +1 -1
  28. package/registry/navigation-menu.json +1 -1
  29. package/registry/number-input.json +1 -1
  30. package/registry/package-manager-tabs.json +24 -0
  31. package/registry/pager.json +21 -0
  32. package/registry/popover.json +4 -1
  33. package/registry/resizable.json +1 -1
  34. package/registry/rich-text-editor.json +95 -0
  35. package/registry/scroll-area.json +1 -1
  36. package/registry/section-heading.json +21 -0
  37. package/registry/select.json +3 -2
  38. package/registry/sheet.json +1 -1
  39. package/registry/sidebar.json +1 -1
  40. package/registry/status.json +1 -1
  41. package/registry/steps.json +20 -0
  42. package/registry/switch.json +4 -1
  43. package/registry/table-of-contents.json +23 -0
  44. package/registry/tabs.json +4 -1
  45. package/registry/theme-manager.json +6 -5
  46. package/registry/titlebar-tabs.json +24 -0
  47. package/registry/titlebar.json +26 -0
  48. package/registry/toggle-group.json +1 -1
  49. package/registry/updater-modal.json +26 -0
  50. package/src/index.ts +48 -0
  51. package/src/registry/components/ui/api-table.tsx +117 -0
  52. package/src/registry/components/ui/banner.tsx +0 -2
  53. package/src/registry/components/ui/button.tsx +1 -1
  54. package/src/registry/components/ui/callout.tsx +137 -0
  55. package/src/registry/components/ui/checkbox.tsx +1 -1
  56. package/src/registry/components/ui/code-block.tsx +326 -0
  57. package/src/registry/components/ui/code-group.tsx +105 -0
  58. package/src/registry/components/ui/combobox.tsx +83 -18
  59. package/src/registry/components/ui/command.tsx +110 -106
  60. package/src/registry/components/ui/component-viewer.tsx +363 -0
  61. package/src/registry/components/ui/container.tsx +45 -0
  62. package/src/registry/components/ui/context-menu.tsx +67 -22
  63. package/src/registry/components/ui/dialog.tsx +42 -32
  64. package/src/registry/components/ui/dropdown-menu.tsx +69 -31
  65. package/src/registry/components/ui/field.tsx +7 -3
  66. package/src/registry/components/ui/file-tree.tsx +181 -0
  67. package/src/registry/components/ui/footer.tsx +1 -1
  68. package/src/registry/components/ui/form-message.tsx +2 -2
  69. package/src/registry/components/ui/icon-button.tsx +1 -1
  70. package/src/registry/components/ui/navbar.tsx +18 -11
  71. package/src/registry/components/ui/navigation-menu.tsx +2 -2
  72. package/src/registry/components/ui/number-input.tsx +3 -3
  73. package/src/registry/components/ui/package-manager-tabs.tsx +226 -0
  74. package/src/registry/components/ui/pager.tsx +102 -0
  75. package/src/registry/components/ui/popover.tsx +1 -1
  76. package/src/registry/components/ui/resizable.tsx +3 -1
  77. package/src/registry/components/ui/rich-text-editor/bubble-menu.tsx +236 -0
  78. package/src/registry/components/ui/rich-text-editor/editor.tsx +308 -0
  79. package/src/registry/components/ui/rich-text-editor/extensions.ts +116 -0
  80. package/src/registry/components/ui/rich-text-editor/footer.tsx +36 -0
  81. package/src/registry/components/ui/rich-text-editor/image-dialog.tsx +75 -0
  82. package/src/registry/components/ui/rich-text-editor/index.ts +11 -0
  83. package/src/registry/components/ui/rich-text-editor/link-dialog.tsx +48 -0
  84. package/src/registry/components/ui/rich-text-editor/markdown.ts +170 -0
  85. package/src/registry/components/ui/rich-text-editor/slash-command.tsx +301 -0
  86. package/src/registry/components/ui/rich-text-editor/table-controls.tsx +68 -0
  87. package/src/registry/components/ui/rich-text-editor/toolbar.tsx +465 -0
  88. package/src/registry/components/ui/rich-text-editor/use-editor.ts +231 -0
  89. package/src/registry/components/ui/scroll-area.tsx +12 -2
  90. package/src/registry/components/ui/section-heading.tsx +108 -0
  91. package/src/registry/components/ui/select.tsx +16 -19
  92. package/src/registry/components/ui/sheet.tsx +58 -53
  93. package/src/registry/components/ui/sidebar.tsx +4 -4
  94. package/src/registry/components/ui/status.tsx +7 -5
  95. package/src/registry/components/ui/steps.tsx +198 -0
  96. package/src/registry/components/ui/switch.tsx +1 -1
  97. package/src/registry/components/ui/table-of-contents.tsx +131 -0
  98. package/src/registry/components/ui/tabs.tsx +1 -1
  99. package/src/registry/components/ui/theme-toggle.tsx +175 -139
  100. package/src/registry/components/ui/titlebar-tabs.tsx +773 -0
  101. package/src/registry/components/ui/titlebar.tsx +468 -0
  102. package/src/registry/components/ui/toggle-group.tsx +1 -1
  103. package/src/registry/components/ui/updater-modal.tsx +254 -0
  104. package/src/registry/metadata.ts +167 -6
  105. package/src/registry/providers/theme-provider.tsx +16 -8
  106. package/src/registry/providers/theme-script.tsx +29 -9
  107. package/src/registry/providers/theme-transitions.ts +81 -50
@@ -0,0 +1,198 @@
1
+ import {
2
+ createContext,
3
+ useContext,
4
+ splitProps,
5
+ Show,
6
+ type JSX,
7
+ type ParentComponent,
8
+ } from "solid-js";
9
+ import { Badge, type BadgeProps } from "@/components/ui/badge";
10
+ import { cn } from "@/lib/cn";
11
+
12
+ export type StepVariant =
13
+ | "default"
14
+ | "primary"
15
+ | "info"
16
+ | "success"
17
+ | "warning"
18
+ | "danger"
19
+ | "secondary"
20
+ | "outline"
21
+ | "destructive"
22
+ | "purple";
23
+
24
+ function toBadgeVariant(variant?: StepVariant): NonNullable<BadgeProps["variant"]> {
25
+ switch (variant) {
26
+ case "primary":
27
+ return "default";
28
+ case "danger":
29
+ return "destructive";
30
+ case "default":
31
+ return "outline";
32
+ case "info":
33
+ return "info";
34
+ case "success":
35
+ return "success";
36
+ case "warning":
37
+ return "warning";
38
+ case "secondary":
39
+ return "secondary";
40
+ default:
41
+ return "outline";
42
+ }
43
+ }
44
+ export type StepOrientation = "horizontal" | "vertical";
45
+
46
+ interface StepsContextValue {
47
+ variant?: StepVariant;
48
+ orientation?: () => StepOrientation;
49
+ }
50
+
51
+ const StepsContext = createContext<StepsContextValue>();
52
+
53
+ export interface StepsProps extends JSX.HTMLAttributes<HTMLDivElement> {
54
+ /** Layout orientation: vertical (default) or horizontal */
55
+ orientation?: StepOrientation;
56
+ /** Default color variant for all steps in this container */
57
+ variant?: StepVariant;
58
+ class?: string;
59
+ }
60
+
61
+ /**
62
+ * Multi-step instruction and stepper container supporting vertical and horizontal layouts.
63
+ */
64
+ export const Steps: ParentComponent<StepsProps> = (props) => {
65
+ const [local, rest] = splitProps(props, ["orientation", "variant", "class", "children"]);
66
+
67
+ const orientation = () => local.orientation || "vertical";
68
+
69
+ return (
70
+ <StepsContext.Provider value={{ variant: local.variant, orientation }}>
71
+ <div
72
+ class={cn(
73
+ "relative my-6 [counter-reset:step]",
74
+ orientation() === "horizontal"
75
+ ? "flex flex-row items-start justify-between w-full"
76
+ : "ml-4 border-l border-border/80 pl-8 space-y-8",
77
+ local.class
78
+ )}
79
+ {...rest}
80
+ >
81
+ {/* Single continuous horizontal rail in parent container */}
82
+ <Show when={orientation() === "horizontal"}>
83
+ <div class="absolute left-8 right-8 top-3.5 h-0.5 bg-border/80 z-0" />
84
+ </Show>
85
+
86
+ {local.children}
87
+ </div>
88
+ </StepsContext.Provider>
89
+ );
90
+ };
91
+
92
+ export interface StepProps extends JSX.HTMLAttributes<HTMLDivElement> {
93
+ /** Optional custom step number, icon, or label to override automatic CSS counter */
94
+ step?: string | number | JSX.Element;
95
+ /** Optional step title rendered at the top of the step */
96
+ title?: string;
97
+ /** Step color variant */
98
+ variant?: StepVariant;
99
+ class?: string;
100
+ }
101
+
102
+ export const Step: ParentComponent<StepProps> = (props) => {
103
+ const [local, rest] = splitProps(props, ["step", "title", "variant", "class", "children"]);
104
+ const context = useContext(StepsContext);
105
+
106
+ const effectiveVariant = () => local.variant || context?.variant || "default";
107
+ const isHorizontal = () => context?.orientation?.() === "horizontal";
108
+
109
+ return (
110
+ <Show
111
+ when={isHorizontal()}
112
+ fallback={
113
+ <div class={cn("relative", local.class)} {...rest}>
114
+ {/* Numbered Step Badge with geometric center on left vertical border line */}
115
+ <Badge
116
+ variant={toBadgeVariant(effectiveVariant())}
117
+ class={cn(
118
+ "absolute -left-[2.875rem] top-0 size-7 p-0 flex items-center justify-center rounded-lg font-mono text-xs font-semibold shadow-2xs select-none",
119
+ !local.step && "[counter-increment:step] before:content-[counter(step)]"
120
+ )}
121
+ >
122
+ <Show when={local.step}>
123
+ {local.step}
124
+ </Show>
125
+ </Badge>
126
+
127
+ {/* Step Title Header */}
128
+ <Show when={local.title}>
129
+ <h4 class="font-semibold text-base tracking-tight text-foreground mb-2">
130
+ {local.title}
131
+ </h4>
132
+ </Show>
133
+
134
+ {/* Step Body Content */}
135
+ <div class="text-sm leading-relaxed text-muted-foreground space-y-3">
136
+ {local.children}
137
+ </div>
138
+ </div>
139
+ }
140
+ >
141
+ <div class={cn("flex-1 flex flex-col items-center text-center relative z-10 px-2", local.class)} {...rest}>
142
+ {/* Step Badge sitting on top of continuous parent rail */}
143
+ <Badge
144
+ variant={toBadgeVariant(effectiveVariant())}
145
+ class={cn(
146
+ "mb-2.5 size-7 p-0 flex items-center justify-center rounded-lg font-mono text-xs font-semibold shadow-2xs select-none",
147
+ !local.step && "[counter-increment:step] before:content-[counter(step)]"
148
+ )}
149
+ >
150
+ <Show when={local.step}>
151
+ {local.step}
152
+ </Show>
153
+ </Badge>
154
+
155
+ {/* Step Title Header */}
156
+ <Show when={local.title}>
157
+ <h4 class="font-semibold text-sm tracking-tight text-foreground mb-1">
158
+ {local.title}
159
+ </h4>
160
+ </Show>
161
+
162
+ {/* Step Body Content */}
163
+ <div class="text-xs leading-relaxed text-muted-foreground">
164
+ {local.children}
165
+ </div>
166
+ </div>
167
+ </Show>
168
+ );
169
+ };
170
+
171
+ export interface StepTitleProps extends JSX.HTMLAttributes<HTMLHeadingElement> {
172
+ class?: string;
173
+ }
174
+
175
+ export const StepTitle: ParentComponent<StepTitleProps> = (props) => {
176
+ const [local, rest] = splitProps(props, ["class", "children"]);
177
+ return (
178
+ <h4
179
+ class={cn("font-semibold text-base tracking-tight text-foreground mb-2", local.class)}
180
+ {...rest}
181
+ >
182
+ {local.children}
183
+ </h4>
184
+ );
185
+ };
186
+
187
+ export interface StepDescriptionProps extends JSX.HTMLAttributes<HTMLParagraphElement> {
188
+ class?: string;
189
+ }
190
+
191
+ export const StepDescription: ParentComponent<StepDescriptionProps> = (props) => {
192
+ const [local, rest] = splitProps(props, ["class", "children"]);
193
+ return (
194
+ <div class={cn("text-sm leading-relaxed text-muted-foreground", local.class)} {...rest}>
195
+ {local.children}
196
+ </div>
197
+ );
198
+ };
@@ -1,5 +1,5 @@
1
1
  import { splitProps, type Component, type JSX } from "solid-js";
2
- import { createControllableSignal } from "@nikala-ui/hooks";
2
+ import { createControllableSignal } from "@/hooks/create-controllable-signal";
3
3
  import { cn } from "@/lib/cn";
4
4
 
5
5
  export interface SwitchProps
@@ -0,0 +1,131 @@
1
+ // src/components/ui/table-of-contents.tsx
2
+ import {
3
+ splitProps,
4
+ createSignal,
5
+ createEffect,
6
+ onMount,
7
+ onCleanup,
8
+ For,
9
+ Show,
10
+ type Component,
11
+ type JSX,
12
+ } from "solid-js";
13
+ import { ScrollArea } from "@/components/ui/scroll-area";
14
+ import { List, ListHeader, ListItem } from "@/components/ui/list";
15
+ import { cn } from "@/lib/cn";
16
+ import { createScrollPosition } from "@/hooks/create-scroll-position";
17
+
18
+ export interface TocItem {
19
+ id: string;
20
+ text: string;
21
+ depth: number;
22
+ }
23
+
24
+ export interface TableOfContentsProps extends Omit<JSX.HTMLAttributes<HTMLDivElement>, "title"> {
25
+ items: TocItem[];
26
+ title?: string | false;
27
+ activeId?: string;
28
+ onItemClick?: (id: string) => void;
29
+ class?: string;
30
+ }
31
+
32
+ /**
33
+ * Nikala UI TableOfContents Component.
34
+ * Pure composition of ScrollArea, ListHeader, List, and ListItem with active ScrollSpy tracking.
35
+ */
36
+ export const TableOfContents: Component<TableOfContentsProps> = (props) => {
37
+ const [local, rest] = splitProps(props, [
38
+ "items",
39
+ "title",
40
+ "activeId",
41
+ "onItemClick",
42
+ "class",
43
+ ]);
44
+
45
+ const [activeId, setActiveId] = createSignal<string>(local.activeId || "");
46
+ const scrollPosition = createScrollPosition();
47
+
48
+ onMount(() => {
49
+ if (typeof window === "undefined" || typeof document === "undefined") return;
50
+
51
+ const headings = (local.items || [])
52
+ .map((item) => document.getElementById(item.id))
53
+ .filter((element): element is HTMLElement => Boolean(element));
54
+
55
+ const updateActiveHeading = () => {
56
+ if (headings.length === 0) return;
57
+
58
+ const atPageBottom = scrollPosition.isAtBottom();
59
+ if (atPageBottom) {
60
+ setActiveId(headings[headings.length - 1].id);
61
+ return;
62
+ }
63
+
64
+ const heading = [...headings]
65
+ .reverse()
66
+ .find((element) => element.getBoundingClientRect().top <= 120);
67
+
68
+ setActiveId(heading?.id || headings[0].id);
69
+ };
70
+
71
+ createEffect(() => {
72
+ scrollPosition.y();
73
+ scrollPosition.isAtBottom();
74
+ updateActiveHeading();
75
+ });
76
+
77
+ window.addEventListener("resize", updateActiveHeading);
78
+ onCleanup(() => window.removeEventListener("resize", updateActiveHeading));
79
+ });
80
+
81
+ const handleClick = (e: MouseEvent, id: string) => {
82
+ if (typeof document !== "undefined") {
83
+ const el = document.getElementById(id);
84
+ if (el) {
85
+ e.preventDefault();
86
+ el.scrollIntoView({ behavior: "smooth" });
87
+ setActiveId(id);
88
+ if (typeof window !== "undefined") {
89
+ window.history.pushState(null, "", `#${id}`);
90
+ }
91
+ }
92
+ }
93
+ local.onItemClick?.(id);
94
+ };
95
+
96
+ return (
97
+ <ScrollArea class={cn("h-full py-2", local.class)} {...rest}>
98
+ <Show when={local.title !== false}>
99
+ <ListHeader
100
+ title={typeof local.title === "string" ? local.title : "On this page"}
101
+ class="px-3 pb-1"
102
+ />
103
+ </Show>
104
+
105
+ <List class="gap-0.5 p-1">
106
+ <For each={local.items}>
107
+ {(item) => (
108
+ <ListItem
109
+ title={item.text}
110
+ href={`#${item.id}`}
111
+ active={activeId() === item.id}
112
+ size="sm"
113
+ hoverVariant="muted"
114
+ class={cn(
115
+ "text-xs transition-colors py-1 h-auto min-h-0",
116
+ item.depth === 3 && "pl-5 text-muted-foreground/80",
117
+ item.depth > 3 && "pl-7 text-muted-foreground/60",
118
+ activeId() === item.id
119
+ ? "text-primary font-medium bg-primary/10"
120
+ : "text-muted-foreground hover:text-foreground"
121
+ )}
122
+ onClick={(e: MouseEvent) => handleClick(e, item.id)}
123
+ />
124
+ )}
125
+ </For>
126
+ </List>
127
+ </ScrollArea>
128
+ );
129
+ };
130
+
131
+ export const Toc = TableOfContents;
@@ -7,7 +7,7 @@ import {
7
7
  type JSX,
8
8
  type Accessor,
9
9
  } from "solid-js";
10
- import { createControllableSignal } from "@nikala-ui/hooks";
10
+ import { createControllableSignal } from "@/hooks/create-controllable-signal";
11
11
  import { cn } from "@/lib/cn";
12
12
 
13
13
  interface TabsContextValue {