remix 3.0.0-beta.0 → 3.0.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.
Files changed (88) hide show
  1. package/dist/fetch-router.d.ts +7 -0
  2. package/dist/fetch-router.d.ts.map +1 -1
  3. package/dist/node-tsx/load-module.d.ts +2 -0
  4. package/dist/node-tsx/load-module.d.ts.map +1 -0
  5. package/dist/node-tsx/load-module.js +2 -0
  6. package/dist/node-tsx.d.ts +3 -0
  7. package/dist/node-tsx.d.ts.map +1 -0
  8. package/{src/node-serve.ts → dist/node-tsx.js} +2 -1
  9. package/dist/render-middleware.d.ts +2 -0
  10. package/dist/render-middleware.d.ts.map +1 -0
  11. package/dist/render-middleware.js +2 -0
  12. package/dist/route-pattern/href.d.ts +2 -0
  13. package/dist/route-pattern/href.d.ts.map +1 -0
  14. package/dist/route-pattern/href.js +2 -0
  15. package/dist/route-pattern/join.d.ts +2 -0
  16. package/dist/route-pattern/join.d.ts.map +1 -0
  17. package/dist/route-pattern/join.js +2 -0
  18. package/dist/route-pattern/match.d.ts +2 -0
  19. package/dist/route-pattern/match.d.ts.map +1 -0
  20. package/dist/route-pattern/match.js +2 -0
  21. package/package.json +158 -44
  22. package/src/assert/README.md +109 -0
  23. package/src/assets/README.md +539 -0
  24. package/src/async-context-middleware/README.md +100 -0
  25. package/src/auth/README.md +445 -0
  26. package/src/auth-middleware/README.md +246 -0
  27. package/src/cli/README.md +78 -0
  28. package/src/compression-middleware/README.md +176 -0
  29. package/src/cookie/README.md +106 -0
  30. package/src/cop-middleware/README.md +117 -0
  31. package/src/cors-middleware/README.md +174 -0
  32. package/src/csrf-middleware/README.md +99 -0
  33. package/src/data-schema/README.md +422 -0
  34. package/src/data-table/README.md +552 -0
  35. package/src/data-table-mysql/README.md +97 -0
  36. package/src/data-table-postgres/README.md +74 -0
  37. package/src/data-table-sqlite/README.md +84 -0
  38. package/src/fetch-proxy/README.md +46 -0
  39. package/src/fetch-router/README.md +902 -0
  40. package/src/fetch-router.ts +7 -0
  41. package/src/file-storage/README.md +57 -0
  42. package/src/file-storage-s3/README.md +47 -0
  43. package/src/form-data-middleware/README.md +109 -0
  44. package/src/form-data-parser/README.md +160 -0
  45. package/src/fs/README.md +60 -0
  46. package/src/headers/README.md +629 -0
  47. package/src/html-template/README.md +101 -0
  48. package/src/lazy-file/README.md +109 -0
  49. package/src/logger-middleware/README.md +132 -0
  50. package/src/method-override-middleware/README.md +71 -0
  51. package/src/mime/README.md +110 -0
  52. package/src/multipart-parser/README.md +241 -0
  53. package/src/node-fetch-server/README.md +352 -0
  54. package/src/node-tsx/README.md +79 -0
  55. package/src/node-tsx/load-module.ts +2 -0
  56. package/{dist/node-serve.js → src/node-tsx.ts} +2 -1
  57. package/src/render-middleware/README.md +99 -0
  58. package/src/render-middleware.ts +2 -0
  59. package/src/route-pattern/README.md +291 -0
  60. package/src/route-pattern/href.ts +2 -0
  61. package/src/route-pattern/join.ts +2 -0
  62. package/src/route-pattern/match.ts +2 -0
  63. package/src/session/README.md +171 -0
  64. package/src/session-middleware/README.md +109 -0
  65. package/src/session-storage-memcache/README.md +37 -0
  66. package/src/session-storage-redis/README.md +37 -0
  67. package/src/static-middleware/README.md +89 -0
  68. package/src/tar-parser/README.md +74 -0
  69. package/src/terminal/README.md +92 -0
  70. package/src/test/README.md +430 -0
  71. package/src/ui/README.md +219 -0
  72. package/src/ui/accordion/README.md +166 -0
  73. package/src/ui/anchor/README.md +153 -0
  74. package/src/ui/animation/README.md +316 -0
  75. package/src/ui/breadcrumbs/README.md +55 -0
  76. package/src/ui/button/README.md +44 -0
  77. package/src/ui/combobox/README.md +145 -0
  78. package/src/ui/glyph/README.md +72 -0
  79. package/src/ui/listbox/README.md +115 -0
  80. package/src/ui/menu/README.md +96 -0
  81. package/src/ui/popover/README.md +122 -0
  82. package/src/ui/scroll-lock/README.md +33 -0
  83. package/src/ui/select/README.md +107 -0
  84. package/src/ui/server/README.md +90 -0
  85. package/src/ui/test/README.md +107 -0
  86. package/src/ui/theme/README.md +103 -0
  87. package/dist/node-serve.d.ts +0 -2
  88. package/dist/node-serve.d.ts.map +0 -1
@@ -0,0 +1,107 @@
1
+ # select
2
+
3
+ `Select` is a button-triggered popup value picker backed by `listbox` and `popover`. Use it when the user should choose one stable string value from a finite set.
4
+
5
+ ## Usage
6
+
7
+ ```tsx
8
+ import { Option, Select, onSelectChange } from 'remix/ui/select'
9
+
10
+ export function FrameworkSelect() {
11
+ return (
12
+ <Select
13
+ defaultLabel="Select a framework"
14
+ defaultValue="remix"
15
+ name="framework"
16
+ mix={onSelectChange((event) => {
17
+ console.log(event.value, event.label, event.optionId)
18
+ })}
19
+ >
20
+ <Option label="Remix framework" value="remix">
21
+ Remix
22
+ </Option>
23
+ <Option disabled label="React Router framework" value="react-router">
24
+ React Router
25
+ </Option>
26
+ <Option label="React framework" value="react">
27
+ React
28
+ </Option>
29
+ </Select>
30
+ )
31
+ }
32
+ ```
33
+
34
+ Use `textValue` when closed-trigger typeahead should match a different string from the visible label.
35
+
36
+ ```tsx
37
+ <Select defaultLabel="Select an environment">
38
+ <Option label="Production environment" value="production">
39
+ Production
40
+ </Option>
41
+ <Option label="Staging environment" textValue="beta" value="staging">
42
+ Staging
43
+ </Option>
44
+ </Select>
45
+ ```
46
+
47
+ Use the lower-level primitives when the trigger or popup structure needs to be owned by another component. Keep the same provider, trigger, popover, list, option, and hidden-input relationship.
48
+
49
+ ```tsx
50
+ import type { Handle } from 'remix/ui'
51
+ import * as button from 'remix/ui/button'
52
+ import * as listbox from 'remix/ui/listbox'
53
+ import * as popover from 'remix/ui/popover'
54
+ import * as select from 'remix/ui/select'
55
+
56
+ function SelectValue(handle: Handle) {
57
+ let context = handle.context.get(select.Context)
58
+
59
+ return () => <span mix={button.labelStyle}>{context.displayedLabel}</span>
60
+ }
61
+
62
+ function IssueTypeSelect() {
63
+ return () => (
64
+ <select.Context defaultLabel="Select a type" name="issueType">
65
+ <button type="button" mix={[button.baseStyle, select.triggerStyle, select.trigger()]}>
66
+ <SelectValue />
67
+ </button>
68
+ <popover.Context>
69
+ <div mix={[popover.surfaceStyle, select.popover()]}>
70
+ <div mix={[popover.contentStyle, listbox.listStyle, select.list()]}>
71
+ <div mix={[listbox.optionStyle, select.option({ label: 'Bug', value: 'bug' })]}>
72
+ Bug
73
+ </div>
74
+ <div mix={[listbox.optionStyle, select.option({ label: 'Feature', value: 'feature' })]}>
75
+ Feature
76
+ </div>
77
+ </div>
78
+ </div>
79
+ </popover.Context>
80
+ <input mix={select.hiddenInput()} />
81
+ </select.Context>
82
+ )
83
+ }
84
+ ```
85
+
86
+ ## `select.*`
87
+
88
+ - `Select`: composed trigger, popover, listbox, option list, and optional hidden input for form participation. Accepts `defaultLabel`, `defaultValue`, `disabled`, `name`, and button props.
89
+ - `Option`: option wrapper that renders the standard check glyph and label slot. Accepts `label`, `value`, optional `disabled`, and optional `textValue`.
90
+ - `onSelectChange(...)`: event mixin for the bubbling `SelectChangeEvent`.
91
+ - `Context`, `trigger()`, `popover()`, `list()`, `option(...)`, and `hiddenInput()`: lower-level composition primitives.
92
+ - `triggerStyle`: standard select trigger style.
93
+ - `SelectChangeEvent`: event with `value`, `label`, and `optionId`.
94
+ - `SelectProps`, `SelectContextProps`, and `SelectOptionProps`: public TypeScript props for the composed and lower-level APIs.
95
+
96
+ ## Behavior Notes
97
+
98
+ - `defaultLabel` is displayed before selection settles. `defaultValue` selects the matching option without replacing the trigger label until a new selection commits.
99
+ - `Option.label` is the committed display label and event label. `children` are the rendered option contents.
100
+ - Click, `ArrowDown`, and `ArrowUp` open the popup. Focus moves into the list and Escape restores focus to the trigger through popover behavior.
101
+ - Reopening highlights the current selected value.
102
+ - The popup min-width syncs to the trigger width before opening.
103
+ - Closed-trigger typeahead selects a matching option immediately and supports option `textValue`.
104
+ - Selecting an option flashes it with `data-select-flash`, waits for the close transition and label delay, updates the displayed label, and dispatches `SelectChangeEvent`.
105
+ - Selecting the already-selected value updates state but does not dispatch a change event.
106
+ - `SelectChangeEvent` bubbles from the trigger when a trigger exists. It includes `value`, `label`, and `optionId`.
107
+ - Passing `name` renders a hidden input so the selected value participates in `FormData`; disabled selects disable the trigger and hidden input.
@@ -0,0 +1,90 @@
1
+ # Server
2
+
3
+ Remix UI can render to HTML on the server using two APIs:
4
+
5
+ - `renderToString` - Returns a complete HTML string. Simple, but buffers the entire response.
6
+ - `renderToStream` - Returns a `ReadableStream<Uint8Array>`. Sends the initial HTML immediately and streams frame content as it resolves.
7
+
8
+ Both are exported from `remix/ui/server`.
9
+
10
+ ## renderToString
11
+
12
+ Renders a component tree to a complete HTML string. Use this when you need the full output before responding (e.g., generating static pages or embedding HTML in an email).
13
+
14
+ ```tsx
15
+ import { renderToString } from 'remix/ui/server'
16
+
17
+ let html = await renderToString(<App />)
18
+ ```
19
+
20
+ ## renderToStream
21
+
22
+ Renders a component tree to a streaming response. The initial HTML is sent immediately. Any `<Frame>` components with a `fallback` prop will render the fallback first, then stream the resolved content as it becomes available.
23
+
24
+ ```tsx
25
+ import { renderToStream } from 'remix/ui/server'
26
+
27
+ let stream = renderToStream(<App />, {
28
+ frameSrc: request.url,
29
+ signal: request.signal,
30
+ resolveFrame(src, _target, context) {
31
+ let frameUrl = new URL(src, context?.currentFrameSrc ?? request.url)
32
+ return fetchHtml(frameUrl)
33
+ },
34
+ onError(error) {
35
+ console.error(error)
36
+ },
37
+ })
38
+
39
+ return new Response(stream, {
40
+ headers: { 'Content-Type': 'text/html; charset=utf-8' },
41
+ })
42
+ ```
43
+
44
+ ### Options
45
+
46
+ - **`frameSrc`** - Seeds SSR frame state for the current render. When provided, server-rendered components can read `handle.frame.src` and `handle.frames.top.src` during SSR.
47
+ - **`topFrameSrc`** - Overrides the root frame URL used for `handle.frames.top.src`. This is mainly useful when calling `renderToStream()` from inside `resolveFrame()` for a nested frame render.
48
+ - **`signal`** - Cancels pending server rendering work. Pass `request.signal` so client disconnects can stop unresolved frame work without invoking `onError` for the disconnect itself.
49
+ - **`resolveFrame(src, target, context)`** - Called when a `<Frame>` needs its content. Return a string of HTML, a `ReadableStream<Uint8Array>`, or a promise of either. `context.currentFrameSrc` is the URL for the frame that contains the `<Frame>`, and `context.topFrameSrc` is the outer document URL. Required if your component tree contains `<Frame>` elements.
50
+ - **`onError(error)`** - Called when a rendering error occurs. If not provided, the stream rejects with the error.
51
+
52
+ When you render nested frame responses with `renderToStream()` inside `resolveFrame()`, pass `frameSrc` for the frame being rendered and carry `topFrameSrc` forward from the parent context. That preserves `handle.frames.top.src` across the whole SSR frame tree.
53
+
54
+ ### Streaming behavior
55
+
56
+ When the stream encounters a `<Frame>` component:
57
+
58
+ - **Without `fallback`** (blocking): The frame content is awaited before the initial HTML chunk is sent. The resolved content appears inline.
59
+ - **With `fallback`** (non-blocking): The fallback is rendered inline in the initial chunk. Once the frame resolves, a `<template>` element containing the real content is streamed at the end of the response. The client swaps it in automatically.
60
+
61
+ This means the first chunk always contains a complete, renderable page. Slow data sources don't block the initial paint.
62
+
63
+ ## Head content
64
+
65
+ To render content into the document head during SSR, use an explicit `<head>` element:
66
+
67
+ ```tsx
68
+ function ProductPage() {
69
+ return () => (
70
+ <html>
71
+ <head>
72
+ <title>Product Name</title>
73
+ <meta name="description" content="A great product" />
74
+ </head>
75
+ <body>
76
+ <h1>Product Name</h1>
77
+ </body>
78
+ </html>
79
+ )
80
+ }
81
+ ```
82
+
83
+ ## CSS
84
+
85
+ Components using the `css(...)` mixin through `mix` have their styles collected during rendering and emitted as a single `<style>` tag in the `<head>`. No client-side style injection is needed for server-rendered content.
86
+
87
+ ## See Also
88
+
89
+ - [Hydration](https://github.com/remix-run/remix/blob/main/packages/ui/docs/hydration.md) - Making server-rendered components interactive on the client
90
+ - [Frames](https://github.com/remix-run/remix/blob/main/packages/ui/docs/frames.md) - Streaming partial server UI with `<Frame>`
@@ -0,0 +1,107 @@
1
+ # Test
2
+
3
+ When writing tests, use `root.flush()` to synchronously execute all pending updates and tasks. This ensures the DOM and component state are fully synchronized before making assertions.
4
+
5
+ ## Basic Testing Pattern
6
+
7
+ The main use case is flushing after events that call `handle.update()`. Since updates are asynchronous, you need to flush to ensure the DOM reflects the changes:
8
+
9
+ ```tsx
10
+ function Counter(handle: Handle) {
11
+ let count = 0
12
+
13
+ return () => (
14
+ <button
15
+ mix={[
16
+ on('click', () => {
17
+ count++
18
+ handle.update()
19
+ }),
20
+ ]}
21
+ >
22
+ Count: {count}
23
+ </button>
24
+ )
25
+ }
26
+
27
+ // In your test
28
+ let container = document.createElement('div')
29
+ let root = createRoot(container)
30
+
31
+ root.render(<Counter />)
32
+ root.flush() // Ensure initial render completes
33
+
34
+ let button = container.querySelector('button')
35
+ button.click() // Triggers handle.update()
36
+ root.flush() // Flush to apply the update
37
+
38
+ expect(container.textContent).toBe('Count: 1')
39
+ ```
40
+
41
+ ## Why Flush After Initial Render?
42
+
43
+ You should also flush after the initial `root.render()` to ensure event listeners are attached and the DOM is ready for interaction:
44
+
45
+ ```tsx
46
+ let root = createRoot(container)
47
+ root.render(<MyComponent />)
48
+ root.flush() // Event listeners now attached
49
+
50
+ // Safe to interact
51
+ container.querySelector('button').click()
52
+ ```
53
+
54
+ ## Testing Async Operations
55
+
56
+ For components with async operations in `queueTask`, flush after each step:
57
+
58
+ ```tsx
59
+ function AsyncLoader(handle: Handle) {
60
+ let data: string | null = null
61
+
62
+ handle.queueTask(async (signal) => {
63
+ let response = await fetch('/api/data', { signal })
64
+ let json = await response.json()
65
+ if (signal.aborted) return
66
+ data = json.value
67
+ handle.update()
68
+ })
69
+
70
+ return () => <div>{data ?? 'Loading...'}</div>
71
+ }
72
+
73
+ // In your test (with mocked fetch)
74
+ let root = createRoot(container)
75
+ root.render(<AsyncLoader />)
76
+ root.flush()
77
+
78
+ expect(container.textContent).toBe('Loading...')
79
+
80
+ // After fetch resolves
81
+ await waitForFetch()
82
+ root.flush()
83
+
84
+ expect(container.textContent).toBe('Expected data')
85
+ ```
86
+
87
+ ## Testing Component Removal
88
+
89
+ Use `root.dispose()` to clean up and verify cleanup behavior:
90
+
91
+ ```tsx
92
+ let root = createRoot(container)
93
+ root.render(<MyComponent />)
94
+ root.flush()
95
+
96
+ // Verify setup behavior
97
+ expect(container.querySelector('.content')).toBeTruthy()
98
+
99
+ // Remove and verify cleanup
100
+ root.dispose()
101
+ expect(container.innerHTML).toBe('')
102
+ ```
103
+
104
+ ## See Also
105
+
106
+ - [Getting Started](https://github.com/remix-run/remix/blob/main/packages/ui/docs/getting-started.md) - Root methods reference
107
+ - [Handle API](https://github.com/remix-run/remix/blob/main/packages/ui/docs/handle.md) - `handle.queueTask()` behavior
@@ -0,0 +1,103 @@
1
+ # theme
2
+
3
+ `theme` provides Remix UI design tokens, theme creation, glyph contracts, and the built-in `RMX_01` preset. Use it to install CSS custom properties once and consume typed token references in component styles.
4
+
5
+ ## Usage
6
+
7
+ ```tsx
8
+ import { createTheme, theme } from 'remix/ui/theme'
9
+ import { css } from 'remix/ui'
10
+
11
+ let Theme = createTheme({
12
+ space: {
13
+ none: '0px',
14
+ px: '1px',
15
+ xs: '2px',
16
+ sm: '4px',
17
+ md: '8px',
18
+ lg: '12px',
19
+ xl: '16px',
20
+ xxl: '24px',
21
+ },
22
+ radius: { none: '0px', sm: '4px', md: '8px', lg: '12px', xl: '16px', full: '9999px' },
23
+ fontFamily: { sans: 'Inter, sans-serif', mono: 'monospace' },
24
+ fontSize: {
25
+ xxxs: '10px',
26
+ xxs: '11px',
27
+ xs: '12px',
28
+ sm: '14px',
29
+ md: '16px',
30
+ lg: '18px',
31
+ xl: '20px',
32
+ xxl: '28px',
33
+ },
34
+ lineHeight: { tight: '1.2', normal: '1.5', relaxed: '1.7' },
35
+ letterSpacing: { tight: '-0.02em', normal: '0', meta: '0.06em', wide: '0.08em' },
36
+ fontWeight: { normal: '400', medium: '500', semibold: '600', bold: '700' },
37
+ control: { height: { sm: '28px', md: '32px', lg: '36px' } },
38
+ surface: { lvl0: '#fff', lvl1: '#f8fafc', lvl2: '#f5f5f5', lvl3: '#f1f5f9', lvl4: '#e9eef6' },
39
+ shadow: { xs: 'none', sm: 'none', md: 'none', lg: 'none', xl: 'none' },
40
+ colors: {
41
+ text: { primary: '#111827', secondary: '#374151', muted: '#6b7280', link: '#2563eb' },
42
+ border: { subtle: '#e5e7eb', default: '#d1d5db', strong: '#9ca3af' },
43
+ focus: { ring: '#3b82f6' },
44
+ overlay: { scrim: 'rgb(0 0 0 / 0.45)' },
45
+ action: {
46
+ primary: {
47
+ background: '#2563eb',
48
+ backgroundHover: '#1d4ed8',
49
+ backgroundActive: '#1e40af',
50
+ foreground: '#fff',
51
+ border: '#2563eb',
52
+ },
53
+ secondary: {
54
+ background: '#fff',
55
+ backgroundHover: '#f8fafc',
56
+ backgroundActive: '#f1f5f9',
57
+ foreground: '#111827',
58
+ border: '#d1d5db',
59
+ },
60
+ danger: {
61
+ background: '#dc2626',
62
+ backgroundHover: '#b91c1c',
63
+ backgroundActive: '#991b1b',
64
+ foreground: '#fff',
65
+ border: '#dc2626',
66
+ },
67
+ },
68
+ },
69
+ })
70
+
71
+ let card = css({
72
+ backgroundColor: theme.surface.lvl0,
73
+ color: theme.colors.text.primary,
74
+ })
75
+
76
+ function Layout() {
77
+ return (
78
+ <body>
79
+ <Theme />
80
+ <article mix={card}>Project status</article>
81
+ </body>
82
+ )
83
+ }
84
+ ```
85
+
86
+ ## `theme.*`
87
+
88
+ - `theme`: typed CSS variable reference contract, such as `theme.space.md` and `theme.colors.text.primary`.
89
+ - `createTheme(values, options?)`: creates a style component with `cssText`, `selector`, `values`, `vars`, and `Style`.
90
+ - `RMX_01`: built-in theme component.
91
+ - `RMX_01_GLYPHS`: built-in glyph sheet component.
92
+ - `glyphContract` and `glyphNames`: stable glyph ids and supported glyph names.
93
+ - `ThemeValues`, `ThemeVars`, `ThemeComponent`, `ThemeStyleProps`, `CreateThemeOptions`, and `ThemeMix`: public TypeScript types for custom themes.
94
+ - `GlyphName`, `GlyphSymbol`, and `GlyphValues`: public TypeScript types for glyph contracts.
95
+
96
+ ## Behavior Notes
97
+
98
+ - `theme` values are CSS variable references, not raw token values.
99
+ - `createTheme` serializes token values into CSS custom properties and renders a `<style data-rmx-theme>` tag.
100
+ - The default selector is `:root`; pass `selector` for scoped themes.
101
+ - The base reset is included by default, emitted in `rmx-reset`, and can be disabled with `reset: false`.
102
+ - The built-in components consume this token contract through their style mixins.
103
+ - Render `<RMX_01 />` and `<RMX_01_GLYPHS />` once when using the built-in theme and glyph preset.
@@ -1,2 +0,0 @@
1
- export * from '@remix-run/node-serve';
2
- //# sourceMappingURL=node-serve.d.ts.map
@@ -1 +0,0 @@
1
- {"version":3,"file":"node-serve.d.ts","sourceRoot":"","sources":["../src/node-serve.ts"],"names":[],"mappings":"AACA,cAAc,uBAAuB,CAAA"}