@weaverclub/render 0.0.2 → 0.0.3

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 (64) hide show
  1. package/dist/entrypoint +0 -0
  2. package/package.json +6 -2
  3. package/.github/workflows/publish.yml +0 -44
  4. package/biome.json +0 -42
  5. package/build.ts +0 -62
  6. package/bun.lock +0 -733
  7. package/bunfig.toml +0 -3
  8. package/ideas.md +0 -11
  9. package/publish.ts +0 -62
  10. package/src/cli/command/renderCommand.ts +0 -112
  11. package/src/cli/entrypoint.ts +0 -25
  12. package/src/core/bundler.ts +0 -180
  13. package/src/core/control/arrayControl.ts +0 -15
  14. package/src/core/control/booleanControl.ts +0 -15
  15. package/src/core/control/control.ts +0 -7
  16. package/src/core/control/controlBuilder.ts +0 -87
  17. package/src/core/control/numberControl.ts +0 -15
  18. package/src/core/control/stringControl.ts +0 -15
  19. package/src/core/control/variantControl.ts +0 -18
  20. package/src/core/css/css.ts +0 -50
  21. package/src/core/css/tailwind.ts +0 -172
  22. package/src/core/html.ts +0 -63
  23. package/src/core/pkg.ts +0 -92
  24. package/src/core/story.ts +0 -52
  25. package/src/core/tsconfig.ts +0 -46
  26. package/src/react/react.ts +0 -2
  27. package/src/react/reactControlBuilder.ts +0 -130
  28. package/src/react/reactStory.ts +0 -36
  29. package/src/server/api/getStories.ts +0 -44
  30. package/src/server/api/renderIframe.ts +0 -66
  31. package/src/server/backend.ts +0 -104
  32. package/src/server/streaming.ts +0 -16
  33. package/src/ui/api.ts +0 -16
  34. package/src/ui/app.tsx +0 -23
  35. package/src/ui/cn.ts +0 -6
  36. package/src/ui/components/appSidebar.tsx +0 -76
  37. package/src/ui/components/button.stories.tsx +0 -32
  38. package/src/ui/components/button.tsx +0 -55
  39. package/src/ui/components/command.tsx +0 -187
  40. package/src/ui/components/contextMenu.tsx +0 -261
  41. package/src/ui/components/dialog.tsx +0 -153
  42. package/src/ui/components/input.tsx +0 -23
  43. package/src/ui/components/inputGroup.tsx +0 -157
  44. package/src/ui/components/kdb.tsx +0 -26
  45. package/src/ui/components/searchCommand.tsx +0 -5
  46. package/src/ui/components/separator.tsx +0 -22
  47. package/src/ui/components/sheet.tsx +0 -131
  48. package/src/ui/components/sidebar.tsx +0 -725
  49. package/src/ui/components/skeleton.tsx +0 -13
  50. package/src/ui/components/spinner.tsx +0 -15
  51. package/src/ui/components/tabButton.tsx +0 -80
  52. package/src/ui/components/tabContent.tsx +0 -20
  53. package/src/ui/components/tabList.tsx +0 -53
  54. package/src/ui/components/textarea.tsx +0 -17
  55. package/src/ui/components/tooltip.tsx +0 -67
  56. package/src/ui/frontend.tsx +0 -68
  57. package/src/ui/hooks/useMobile.ts +0 -23
  58. package/src/ui/index.html +0 -12
  59. package/src/ui/routeTree.gen.ts +0 -35
  60. package/src/ui/routes/__root.tsx +0 -9
  61. package/src/ui/styles.css +0 -123
  62. package/src/ui/tabs.tsx +0 -89
  63. package/tsconfig.json +0 -25
  64. package/tsr.config.json +0 -6
@@ -1,104 +0,0 @@
1
- import { BunContext } from '@effect/platform-bun'
2
- import { Console, Effect } from 'effect'
3
- import type { CSS } from '#core/css/css'
4
- import type { ReactStory } from '#react/reactStory'
5
- import index from '../ui/index.html'
6
- import { getStories } from './api/getStories'
7
- import { renderIframe } from './api/renderIframe'
8
-
9
- // Track connected WebSocket clients for HMR
10
- const hmrClients = new Set<{ send: (msg: string) => void }>()
11
-
12
- export const notifyHmrClients = () => {
13
- for (const client of hmrClients) {
14
- try {
15
- client.send(JSON.stringify({ type: 'reload' }))
16
- } catch {
17
- hmrClients.delete(client)
18
- }
19
- }
20
- }
21
-
22
- // Mutable state for HMR updates
23
- // biome-ignore lint/suspicious/noExplicitAny: Required for story typing
24
- let currentStories: ReactStory<any>[] = []
25
- let currentCss: CSS[] = []
26
- let currentProjectRoot = ''
27
-
28
- export const updateBackendState = ({
29
- stories,
30
- css,
31
- projectRoot
32
- }: StartBackendArgs) => {
33
- currentStories = stories
34
- currentCss = css
35
- currentProjectRoot = projectRoot
36
- }
37
-
38
- export const startBackend = ({ stories, css, projectRoot }: StartBackendArgs) =>
39
- Effect.sync(() => {
40
- // Initialize mutable state
41
- currentStories = stories
42
- currentCss = css
43
- currentProjectRoot = projectRoot
44
-
45
- return Bun.serve({
46
- port: 3210,
47
- routes: {
48
- '/iframe/*': {
49
- GET: (request) =>
50
- Effect.runPromise(
51
- renderIframe({
52
- request,
53
- stories: currentStories,
54
- css: currentCss,
55
- projectRoot: currentProjectRoot
56
- }).pipe(Effect.provide(BunContext.layer))
57
- )
58
- },
59
- '/api/stories': {
60
- GET: (request) =>
61
- Effect.runSync(getStories({ request, stories: currentStories }))
62
- },
63
- // Explicit routes for UI paths
64
- '/': index,
65
- '/index.html': index
66
- },
67
- // @ts-expect-error
68
- fetch(req, server) {
69
- const url = new URL(req.url)
70
-
71
- // Handle WebSocket upgrade for HMR
72
- if (url.pathname === '/__hmr') {
73
- const upgraded = server.upgrade(req)
74
- if (upgraded) return undefined
75
- return new Response('WebSocket upgrade failed', { status: 500 })
76
- }
77
-
78
- // Fall back to index for any other paths (SPA routing)
79
- return index
80
- },
81
- websocket: {
82
- open(ws) {
83
- hmrClients.add(ws)
84
- console.log('🔌 HMR client connected')
85
- },
86
- close(ws) {
87
- hmrClients.delete(ws)
88
- console.log('🔌 HMR client disconnected')
89
- },
90
- message(_ws, _message) {
91
- // No client messages expected
92
- }
93
- }
94
- })
95
- }).pipe(
96
- Effect.tap(() => Console.log('Backend started on http://localhost:3210'))
97
- )
98
-
99
- type StartBackendArgs = {
100
- // biome-ignore lint/suspicious/noExplicitAny: Required for story typing
101
- stories: ReactStory<any>[]
102
- css: CSS[]
103
- projectRoot: string
104
- }
@@ -1,16 +0,0 @@
1
- import { Effect } from 'effect'
2
-
3
- export const streamToString = Effect.fn(function* (stream: ReadableStream) {
4
- const reader = stream.getReader()
5
- const chunks: Uint8Array[] = []
6
-
7
- while (true) {
8
- const { done, value } = yield* Effect.tryPromise(() => reader.read())
9
-
10
- if (done) break
11
-
12
- chunks.push(value)
13
- }
14
-
15
- return new TextDecoder().decode(Buffer.concat(chunks))
16
- })
package/src/ui/api.ts DELETED
@@ -1,16 +0,0 @@
1
- import { QueryClient } from '@tanstack/react-query'
2
-
3
- export const queryClient = new QueryClient()
4
-
5
- export async function getStories(): Promise<GetStoriesResponse> {
6
- return fetch('/api/stories').then((res) => res.json())
7
- }
8
-
9
- export type GetStoriesResponse = {
10
- [category: string]: Story[]
11
- }
12
-
13
- export type Story = {
14
- name: string
15
- path: string
16
- }
package/src/ui/app.tsx DELETED
@@ -1,23 +0,0 @@
1
- import { Tabs } from '@base-ui/react'
2
- import { QueryClientProvider } from '@tanstack/react-query'
3
- import { queryClient } from './api'
4
- import { AppSidebar } from './components/appSidebar'
5
- import { SidebarProvider } from './components/sidebar'
6
- import { TabContent } from './components/tabContent'
7
- import { TabList } from './components/tabList'
8
-
9
- export function App() {
10
- return (
11
- <QueryClientProvider client={queryClient}>
12
- <SidebarProvider>
13
- <AppSidebar />
14
- <main className="flex flex-col w-full">
15
- <Tabs.Root>
16
- <TabList />
17
- <TabContent />
18
- </Tabs.Root>
19
- </main>
20
- </SidebarProvider>
21
- </QueryClientProvider>
22
- )
23
- }
package/src/ui/cn.ts DELETED
@@ -1,6 +0,0 @@
1
- import { type ClassValue, clsx } from 'clsx'
2
- import { twMerge } from 'tailwind-merge'
3
-
4
- export function cn(...inputs: ClassValue[]) {
5
- return twMerge(clsx(inputs))
6
- }
@@ -1,76 +0,0 @@
1
- import { useQuery } from '@tanstack/react-query'
2
- import { getStories } from '#ui/api'
3
- import { Button } from './button'
4
- import { Kbd } from './kdb'
5
- import {
6
- Sidebar,
7
- SidebarContent,
8
- SidebarGroup,
9
- SidebarGroupContent,
10
- SidebarGroupLabel,
11
- SidebarHeader,
12
- SidebarMenu
13
- } from './sidebar'
14
- import { Spinner } from './spinner'
15
- import { TabButton } from './tabButton'
16
-
17
- export function AppSidebar() {
18
- const { data, isLoading, error } = useQuery({
19
- queryKey: ['stories'],
20
- queryFn: getStories
21
- })
22
-
23
- return (
24
- <Sidebar>
25
- <SidebarHeader>
26
- <Button
27
- variant="outline"
28
- size="lg"
29
- className="flex justify-between gap-1 w-full text-zinc-500 font-normal"
30
- >
31
- <span>Search...</span>
32
- <Kbd>⌘ K</Kbd>
33
- </Button>
34
- </SidebarHeader>
35
-
36
- <SidebarContent>
37
- {isLoading && (
38
- <div className="w-full py-8 flex items-center justify-center">
39
- <Spinner />
40
- </div>
41
- )}
42
- {error && (
43
- <div className="w-full py-8 flex flex-col items-center justify-center text-center gap-2">
44
- <p className="text-xs text-destructive font-medium">
45
- Failed to load stories.
46
- </p>
47
- <p className="text-xs text-muted-foreground">
48
- Check if your server is running and accessible.
49
- </p>
50
- </div>
51
- )}
52
- {data &&
53
- Object.keys(data).map((storyGroup) => (
54
- <SidebarGroup key={storyGroup}>
55
- <SidebarGroupLabel>{storyGroup}</SidebarGroupLabel>
56
- <SidebarGroupContent>
57
- <SidebarMenu>
58
- {data[storyGroup]?.map((story) => (
59
- <TabButton
60
- key={story.path}
61
- story={{
62
- id: story.path,
63
- name: story.name
64
- }}
65
- >
66
- <span>{story.name}</span>
67
- </TabButton>
68
- ))}
69
- </SidebarMenu>
70
- </SidebarGroupContent>
71
- </SidebarGroup>
72
- ))}
73
- </SidebarContent>
74
- </Sidebar>
75
- )
76
- }
@@ -1,32 +0,0 @@
1
- import { controls } from '#react/reactControlBuilder'
2
- import { story } from '#react/reactStory'
3
- import { Button } from './button'
4
-
5
- const buttonControls = controls<typeof Button>()
6
- .variant('variant', {
7
- defaultValue: 'default',
8
- options: ['default', 'destructive', 'ghost', 'outline', 'secondary', 'link']
9
- })
10
- .variant('size', {
11
- defaultValue: 'default',
12
- options: [
13
- 'default',
14
- 'xs',
15
- 'sm',
16
- 'lg',
17
- 'icon',
18
- 'icon-xs',
19
- 'icon-sm',
20
- 'icon-lg'
21
- ]
22
- })
23
- .bool('disabled', {
24
- defaultValue: false
25
- })
26
-
27
- export const Story = story({
28
- name: 'UI/Button',
29
- component: Button,
30
- controls: buttonControls,
31
- render: (props) => <Button {...props}>Click me</Button>
32
- })
@@ -1,55 +0,0 @@
1
- import { Button as ButtonPrimitive } from '@base-ui/react/button'
2
- import { cva, type VariantProps } from 'class-variance-authority'
3
- import { cn } from '../cn'
4
-
5
- const buttonVariants = cva(
6
- "focus-visible:border-ring focus-visible:ring-ring/30 aria-invalid:ring-destructive/20 dark:aria-invalid:ring-destructive/40 aria-invalid:border-destructive dark:aria-invalid:border-destructive/50 rounded-md border border-transparent bg-clip-padding text-xs/relaxed font-medium focus-visible:ring-2 aria-invalid:ring-2 [&_svg:not([class*='size-'])]:size-4 inline-flex items-center justify-center whitespace-nowrap transition-all disabled:pointer-events-none disabled:opacity-50 [&_svg]:pointer-events-none shrink-0 [&_svg]:shrink-0 outline-none group/button select-none",
7
- {
8
- variants: {
9
- variant: {
10
- default: 'bg-primary text-primary-foreground hover:bg-primary/80',
11
- outline:
12
- 'border-border dark:bg-input/20 dark:bg-input/30 hover:bg-input/50 hover:text-foreground aria-expanded:bg-muted aria-expanded:text-foreground',
13
- secondary:
14
- 'bg-secondary text-secondary-foreground hover:bg-secondary/80 aria-expanded:bg-secondary aria-expanded:text-secondary-foreground',
15
- ghost:
16
- 'hover:bg-muted hover:text-foreground dark:hover:bg-muted/50 aria-expanded:bg-muted aria-expanded:text-foreground',
17
- destructive:
18
- 'bg-destructive/10 hover:bg-destructive/20 focus-visible:ring-destructive/20 dark:focus-visible:ring-destructive/40 dark:bg-destructive/20 text-destructive focus-visible:border-destructive/40 dark:hover:bg-destructive/30',
19
- link: 'text-primary underline-offset-4 hover:underline'
20
- },
21
- size: {
22
- default:
23
- "h-7 gap-1 px-2 text-xs/relaxed has-data-[icon=inline-end]:pr-1.5 has-data-[icon=inline-start]:pl-1.5 [&_svg:not([class*='size-'])]:size-3.5",
24
- xs: "h-5 gap-1 rounded-sm px-2 text-[0.625rem] has-data-[icon=inline-end]:pr-1.5 has-data-[icon=inline-start]:pl-1.5 [&_svg:not([class*='size-'])]:size-2.5",
25
- sm: "h-6 gap-1 px-2 text-xs/relaxed has-data-[icon=inline-end]:pr-1.5 has-data-[icon=inline-start]:pl-1.5 [&_svg:not([class*='size-'])]:size-3",
26
- lg: "h-8 gap-1 px-2.5 text-xs/relaxed has-data-[icon=inline-end]:pr-2 has-data-[icon=inline-start]:pl-2 [&_svg:not([class*='size-'])]:size-4",
27
- icon: "size-7 [&_svg:not([class*='size-'])]:size-3.5",
28
- 'icon-xs': "size-5 rounded-sm [&_svg:not([class*='size-'])]:size-2.5",
29
- 'icon-sm': "size-6 [&_svg:not([class*='size-'])]:size-3",
30
- 'icon-lg': "size-8 [&_svg:not([class*='size-'])]:size-4"
31
- }
32
- },
33
- defaultVariants: {
34
- variant: 'default',
35
- size: 'default'
36
- }
37
- }
38
- )
39
-
40
- function Button({
41
- className,
42
- variant = 'default',
43
- size = 'default',
44
- ...props
45
- }: ButtonPrimitive.Props & VariantProps<typeof buttonVariants>) {
46
- return (
47
- <ButtonPrimitive
48
- data-slot="button"
49
- className={cn(buttonVariants({ variant, size, className }))}
50
- {...props}
51
- />
52
- )
53
- }
54
-
55
- export { Button, buttonVariants }
@@ -1,187 +0,0 @@
1
- import { Command as CommandPrimitive } from 'cmdk'
2
- import { CheckIcon, SearchIcon } from 'lucide-react'
3
- import type * as React from 'react'
4
- import { cn } from '../cn'
5
- import {
6
- Dialog,
7
- DialogContent,
8
- DialogDescription,
9
- DialogHeader,
10
- DialogTitle
11
- } from './dialog'
12
- import { InputGroup, InputGroupAddon } from './inputGroup'
13
-
14
- function Command({
15
- className,
16
- ...props
17
- }: React.ComponentProps<typeof CommandPrimitive>) {
18
- return (
19
- <CommandPrimitive
20
- data-slot="command"
21
- className={cn(
22
- 'bg-popover text-popover-foreground rounded-xl p-1 flex size-full flex-col overflow-hidden',
23
- className
24
- )}
25
- {...props}
26
- />
27
- )
28
- }
29
-
30
- function CommandDialog({
31
- title = 'Command Palette',
32
- description = 'Search for a command to run...',
33
- children,
34
- className,
35
- showCloseButton = false,
36
- ...props
37
- }: Omit<React.ComponentProps<typeof Dialog>, 'children'> & {
38
- title?: string
39
- description?: string
40
- className?: string
41
- showCloseButton?: boolean
42
- children: React.ReactNode
43
- }) {
44
- return (
45
- <Dialog {...props}>
46
- <DialogHeader className="sr-only">
47
- <DialogTitle>{title}</DialogTitle>
48
- <DialogDescription>{description}</DialogDescription>
49
- </DialogHeader>
50
- <DialogContent
51
- className={cn('rounded-xl! p-0 overflow-hidden p-0', className)}
52
- showCloseButton={showCloseButton}
53
- >
54
- {children}
55
- </DialogContent>
56
- </Dialog>
57
- )
58
- }
59
-
60
- function CommandInput({
61
- className,
62
- ...props
63
- }: React.ComponentProps<typeof CommandPrimitive.Input>) {
64
- return (
65
- <div data-slot="command-input-wrapper" className="p-1 pb-0">
66
- <InputGroup className="bg-input/20 dark:bg-input/30 h-8!">
67
- <CommandPrimitive.Input
68
- data-slot="command-input"
69
- className={cn(
70
- 'w-full text-xs/relaxed outline-hidden disabled:cursor-not-allowed disabled:opacity-50',
71
- className
72
- )}
73
- {...props}
74
- />
75
- <InputGroupAddon>
76
- <SearchIcon className="size-3.5 shrink-0 opacity-50" />
77
- </InputGroupAddon>
78
- </InputGroup>
79
- </div>
80
- )
81
- }
82
-
83
- function CommandList({
84
- className,
85
- ...props
86
- }: React.ComponentProps<typeof CommandPrimitive.List>) {
87
- return (
88
- <CommandPrimitive.List
89
- data-slot="command-list"
90
- className={cn(
91
- 'no-scrollbar max-h-72 scroll-py-1 outline-none overflow-x-hidden overflow-y-auto',
92
- className
93
- )}
94
- {...props}
95
- />
96
- )
97
- }
98
-
99
- function CommandEmpty({
100
- className,
101
- ...props
102
- }: React.ComponentProps<typeof CommandPrimitive.Empty>) {
103
- return (
104
- <CommandPrimitive.Empty
105
- data-slot="command-empty"
106
- className={cn('py-6 text-center text-xs/relaxed', className)}
107
- {...props}
108
- />
109
- )
110
- }
111
-
112
- function CommandGroup({
113
- className,
114
- ...props
115
- }: React.ComponentProps<typeof CommandPrimitive.Group>) {
116
- return (
117
- <CommandPrimitive.Group
118
- data-slot="command-group"
119
- className={cn(
120
- 'text-foreground [&_[cmdk-group-heading]]:text-muted-foreground overflow-hidden p-1 [&_[cmdk-group-heading]]:px-2.5 [&_[cmdk-group-heading]]:py-1.5 [&_[cmdk-group-heading]]:text-xs [&_[cmdk-group-heading]]:font-medium',
121
- className
122
- )}
123
- {...props}
124
- />
125
- )
126
- }
127
-
128
- function CommandSeparator({
129
- className,
130
- ...props
131
- }: React.ComponentProps<typeof CommandPrimitive.Separator>) {
132
- return (
133
- <CommandPrimitive.Separator
134
- data-slot="command-separator"
135
- className={cn('bg-border/50 -mx-1 my-1 h-px', className)}
136
- {...props}
137
- />
138
- )
139
- }
140
-
141
- function CommandItem({
142
- className,
143
- children,
144
- ...props
145
- }: React.ComponentProps<typeof CommandPrimitive.Item>) {
146
- return (
147
- <CommandPrimitive.Item
148
- data-slot="command-item"
149
- className={cn(
150
- "data-selected:bg-muted data-selected:text-foreground data-selected:*:[svg]:text-foreground relative flex min-h-7 cursor-default items-center gap-2 rounded-md px-2.5 py-1.5 text-xs/relaxed outline-hidden select-none [&_svg:not([class*='size-'])]:size-3.5 [[data-slot=dialog-content]_&]:rounded-md group/command-item data-[disabled=true]:pointer-events-none data-[disabled=true]:opacity-50 [&_svg]:pointer-events-none [&_svg]:shrink-0",
151
- className
152
- )}
153
- {...props}
154
- >
155
- {children}
156
- <CheckIcon className="ml-auto opacity-0 group-has-[[data-slot=command-shortcut]]/command-item:hidden group-data-[checked=true]/command-item:opacity-100" />
157
- </CommandPrimitive.Item>
158
- )
159
- }
160
-
161
- function CommandShortcut({
162
- className,
163
- ...props
164
- }: React.ComponentProps<'span'>) {
165
- return (
166
- <span
167
- data-slot="command-shortcut"
168
- className={cn(
169
- 'text-muted-foreground group-data-selected/command-item:text-foreground ml-auto text-[0.625rem] tracking-widest',
170
- className
171
- )}
172
- {...props}
173
- />
174
- )
175
- }
176
-
177
- export {
178
- Command,
179
- CommandDialog,
180
- CommandInput,
181
- CommandList,
182
- CommandEmpty,
183
- CommandGroup,
184
- CommandItem,
185
- CommandShortcut,
186
- CommandSeparator
187
- }