@tempots/dom 26.11.0 → 28.0.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.
- package/dom/browser-context.d.ts +101 -11
- package/dom/dom-context.d.ts +1 -1
- package/index.cjs +1 -1
- package/index.js +619 -474
- package/package.json +1 -1
- package/renderable/ensure.d.ts +72 -9
- package/renderable/foreach.d.ts +56 -6
- package/renderable/not-empty.d.ts +1 -1
- package/renderable/on.d.ts +168 -10
- package/renderable/provider.d.ts +181 -11
- package/renderable/repeat.d.ts +63 -5
- package/renderable/style.d.ts +5 -0
- package/std/signal.d.ts +117 -15
- package/types/domain.d.ts +103 -5
package/package.json
CHANGED
package/renderable/ensure.d.ts
CHANGED
|
@@ -8,21 +8,84 @@ export type Id<T> = {} & {
|
|
|
8
8
|
export type Merge<A, B> = Id<A & B>;
|
|
9
9
|
export type NonNillable<T> = Merge<T, {}>;
|
|
10
10
|
/**
|
|
11
|
-
*
|
|
11
|
+
* Conditionally renders content based on whether a value is non-null/non-undefined.
|
|
12
12
|
*
|
|
13
|
-
*
|
|
14
|
-
*
|
|
15
|
-
*
|
|
16
|
-
*
|
|
17
|
-
* @
|
|
13
|
+
* This function provides a type-safe way to handle nullable values in your UI. It only
|
|
14
|
+
* renders the `then` content when the value is not null or undefined, and optionally
|
|
15
|
+
* renders alternative content when the value is null/undefined.
|
|
16
|
+
*
|
|
17
|
+
* @example
|
|
18
|
+
* ```typescript
|
|
19
|
+
* // With a signal that might be null
|
|
20
|
+
* const user = prop<User | null>(null)
|
|
21
|
+
*
|
|
22
|
+
* Ensure(user,
|
|
23
|
+
* (userSignal) => html.div('Welcome, ', userSignal.map(u => u.name)),
|
|
24
|
+
* () => html.div('Please log in')
|
|
25
|
+
* )
|
|
26
|
+
* ```
|
|
27
|
+
*
|
|
28
|
+
* @example
|
|
29
|
+
* ```typescript
|
|
30
|
+
* // With a literal value
|
|
31
|
+
* const maybeData = getData() // returns string | null
|
|
32
|
+
*
|
|
33
|
+
* Ensure(maybeData,
|
|
34
|
+
* (dataSignal) => html.div('Data: ', dataSignal),
|
|
35
|
+
* () => html.div('No data available')
|
|
36
|
+
* )
|
|
37
|
+
* ```
|
|
38
|
+
*
|
|
39
|
+
* @typeParam T - The type of the value when it's not null/undefined
|
|
40
|
+
* @param value - A signal or literal value that may be null or undefined
|
|
41
|
+
* @param then - Function that receives a signal of the non-nullable value and returns content to render
|
|
42
|
+
* @param otherwise - Optional function that returns content to render when value is null/undefined
|
|
43
|
+
* @returns A renderable that conditionally displays content based on the value's nullability
|
|
18
44
|
* @public
|
|
19
45
|
*/
|
|
20
46
|
export declare const Ensure: <T>(value: NillifyValue<T>, then: (value: Signal<NonNillable<T>>) => TNode, otherwise?: () => TNode) => Renderable;
|
|
21
47
|
/**
|
|
22
|
-
*
|
|
48
|
+
* Conditionally renders content only when ALL provided values are non-null/non-undefined.
|
|
49
|
+
*
|
|
50
|
+
* This function is useful when you need multiple values to be present before rendering content.
|
|
51
|
+
* It waits for all values to be non-null/non-undefined before calling the callback function.
|
|
52
|
+
* If any value becomes null/undefined, it will render the `otherwise` content instead.
|
|
53
|
+
*
|
|
54
|
+
* @example
|
|
55
|
+
* ```typescript
|
|
56
|
+
* const user = prop<User | null>(null)
|
|
57
|
+
* const profile = prop<Profile | null>(null)
|
|
58
|
+
* const settings = prop<Settings | null>(null)
|
|
59
|
+
*
|
|
60
|
+
* EnsureAll(user, profile, settings)(
|
|
61
|
+
* (userSignal, profileSignal, settingsSignal) => html.div(
|
|
62
|
+
* html.h1('Dashboard'),
|
|
63
|
+
* html.div('User: ', userSignal.map(u => u.name)),
|
|
64
|
+
* html.div('Profile: ', profileSignal.map(p => p.bio)),
|
|
65
|
+
* html.div('Theme: ', settingsSignal.map(s => s.theme))
|
|
66
|
+
* ),
|
|
67
|
+
* () => html.div('Loading user data...')
|
|
68
|
+
* )
|
|
69
|
+
* ```
|
|
70
|
+
*
|
|
71
|
+
* @example
|
|
72
|
+
* ```typescript
|
|
73
|
+
* // Mix of signals and literal values
|
|
74
|
+
* const apiData = prop<Data | null>(null)
|
|
75
|
+
* const staticConfig = { theme: 'dark' }
|
|
76
|
+
*
|
|
77
|
+
* EnsureAll(apiData, staticConfig)(
|
|
78
|
+
* (dataSignal, configSignal) => html.div(
|
|
79
|
+
* 'Data loaded with theme: ',
|
|
80
|
+
* configSignal.map(c => c.theme)
|
|
81
|
+
* ),
|
|
82
|
+
* () => html.div('Waiting for data...')
|
|
83
|
+
* )
|
|
84
|
+
* ```
|
|
23
85
|
*
|
|
24
|
-
* @
|
|
25
|
-
* @
|
|
86
|
+
* @typeParam T - Tuple type representing the types of all input values
|
|
87
|
+
* @param signals - Variable number of values (signals or literals) that may be null/undefined
|
|
88
|
+
* @returns A function that takes a callback and optional otherwise function, returning a renderable
|
|
26
89
|
* @public
|
|
27
90
|
*/
|
|
28
91
|
export declare const EnsureAll: <T extends readonly Value<any>[]>(...signals: { [K in keyof T]: NillifyValue<T[K]>; }) => (callback: (...values: { [K in keyof T]: Signal<NonNillable<T[K] extends Value<infer U> ? U : never>>; }) => TNode, otherwise?: () => TNode) => Renderable;
|
package/renderable/foreach.d.ts
CHANGED
|
@@ -3,13 +3,63 @@ import { Signal } from '../std/signal';
|
|
|
3
3
|
import { ElementPosition } from '../std/element-position';
|
|
4
4
|
import { Value } from '../std/value';
|
|
5
5
|
/**
|
|
6
|
-
*
|
|
6
|
+
* Efficiently renders a dynamic list of items from an array signal.
|
|
7
7
|
*
|
|
8
|
-
*
|
|
9
|
-
*
|
|
10
|
-
*
|
|
11
|
-
*
|
|
12
|
-
* @
|
|
8
|
+
* This function creates a reactive list that automatically updates when the source array changes.
|
|
9
|
+
* Each item in the array gets its own signal that tracks changes to that specific item.
|
|
10
|
+
* The list efficiently handles additions, removals, and modifications to the array.
|
|
11
|
+
*
|
|
12
|
+
* @example
|
|
13
|
+
* ```typescript
|
|
14
|
+
* const todos = prop([
|
|
15
|
+
* { id: 1, text: 'Learn Tempo', done: false },
|
|
16
|
+
* { id: 2, text: 'Build an app', done: false }
|
|
17
|
+
* ])
|
|
18
|
+
*
|
|
19
|
+
* ForEach(todos,
|
|
20
|
+
* (todoSignal, position) => html.div(
|
|
21
|
+
* html.input(
|
|
22
|
+
* attr.type('checkbox'),
|
|
23
|
+
* attr.checked(todoSignal.map(t => t.done))
|
|
24
|
+
* ),
|
|
25
|
+
* html.span(todoSignal.map(t => t.text)),
|
|
26
|
+
* html.small(`Item ${position.index + 1}`)
|
|
27
|
+
* )
|
|
28
|
+
* )
|
|
29
|
+
* ```
|
|
30
|
+
*
|
|
31
|
+
* @example
|
|
32
|
+
* ```typescript
|
|
33
|
+
* // With separators between items
|
|
34
|
+
* const items = prop(['apple', 'banana', 'cherry'])
|
|
35
|
+
*
|
|
36
|
+
* ForEach(items,
|
|
37
|
+
* (itemSignal) => html.span(itemSignal),
|
|
38
|
+
* () => html.span(', ') // Separator between items
|
|
39
|
+
* )
|
|
40
|
+
* // Renders: apple, banana, cherry
|
|
41
|
+
* ```
|
|
42
|
+
*
|
|
43
|
+
* @example
|
|
44
|
+
* ```typescript
|
|
45
|
+
* // Using position information
|
|
46
|
+
* const numbers = prop([10, 20, 30])
|
|
47
|
+
*
|
|
48
|
+
* ForEach(numbers,
|
|
49
|
+
* (numberSignal, position) => html.div(
|
|
50
|
+
* `Position ${position.index}: `,
|
|
51
|
+
* numberSignal,
|
|
52
|
+
* position.isFirst ? ' (first)' : '',
|
|
53
|
+
* position.isLast ? ' (last)' : ''
|
|
54
|
+
* )
|
|
55
|
+
* )
|
|
56
|
+
* ```
|
|
57
|
+
*
|
|
58
|
+
* @typeParam T - The type of items in the array
|
|
59
|
+
* @param value - A signal or literal array to iterate over
|
|
60
|
+
* @param item - Function that renders each item, receives the item signal and position info
|
|
61
|
+
* @param separator - Optional function that renders content between items
|
|
62
|
+
* @returns A renderable that displays the dynamic list
|
|
13
63
|
* @public
|
|
14
64
|
*/
|
|
15
65
|
export declare const ForEach: <T>(value: Value<T[]>, item: (value: Signal<T>, position: ElementPosition) => TNode, separator?: (pos: ElementPosition) => TNode) => Renderable;
|
|
@@ -9,7 +9,7 @@ import { Renderable } from '../types/domain';
|
|
|
9
9
|
* @typeParam T - The type of elements in the array.
|
|
10
10
|
* @param value - The signal or literal containing the array.
|
|
11
11
|
* @param display - The component to display when the array is non-empty.
|
|
12
|
-
* @param whenEmpty- The component to display when the array is empty.
|
|
12
|
+
* @param whenEmpty - The component to display when the array is empty.
|
|
13
13
|
* @returns - The renderable component.
|
|
14
14
|
* @public
|
|
15
15
|
*/
|
package/renderable/on.d.ts
CHANGED
|
@@ -7,7 +7,59 @@ import { DOMContext } from '../dom/dom-context';
|
|
|
7
7
|
*/
|
|
8
8
|
export declare const OnChecked: (fn: (event: boolean, ctx: DOMContext) => void) => Renderable;
|
|
9
9
|
/**
|
|
10
|
-
*
|
|
10
|
+
* Provides type-safe event handlers for all HTML events.
|
|
11
|
+
*
|
|
12
|
+
* The `on` object is a proxy that provides access to all standard HTML events with proper
|
|
13
|
+
* TypeScript typing. Each event handler receives the native event object and the DOM context.
|
|
14
|
+
*
|
|
15
|
+
* @example
|
|
16
|
+
* ```typescript
|
|
17
|
+
* // Basic click handler
|
|
18
|
+
* html.button(
|
|
19
|
+
* on.click((event, ctx) => {
|
|
20
|
+
* console.log('Button clicked!', event.target)
|
|
21
|
+
* }),
|
|
22
|
+
* 'Click me'
|
|
23
|
+
* )
|
|
24
|
+
* ```
|
|
25
|
+
*
|
|
26
|
+
* @example
|
|
27
|
+
* ```typescript
|
|
28
|
+
* // Input event with value extraction
|
|
29
|
+
* const text = prop('')
|
|
30
|
+
*
|
|
31
|
+
* html.input(
|
|
32
|
+
* attr.value(text),
|
|
33
|
+
* on.input((event) => {
|
|
34
|
+
* text.value = (event.target as HTMLInputElement).value
|
|
35
|
+
* })
|
|
36
|
+
* )
|
|
37
|
+
* ```
|
|
38
|
+
*
|
|
39
|
+
* @example
|
|
40
|
+
* ```typescript
|
|
41
|
+
* // Multiple event handlers on same element
|
|
42
|
+
* html.div(
|
|
43
|
+
* on.mouseenter(() => console.log('Mouse entered')),
|
|
44
|
+
* on.mouseleave(() => console.log('Mouse left')),
|
|
45
|
+
* on.click(() => console.log('Clicked')),
|
|
46
|
+
* 'Hover and click me'
|
|
47
|
+
* )
|
|
48
|
+
* ```
|
|
49
|
+
*
|
|
50
|
+
* @example
|
|
51
|
+
* ```typescript
|
|
52
|
+
* // Keyboard event handling
|
|
53
|
+
* html.input(
|
|
54
|
+
* on.keydown((event) => {
|
|
55
|
+
* if (event.key === 'Enter') {
|
|
56
|
+
* console.log('Enter pressed!')
|
|
57
|
+
* event.preventDefault()
|
|
58
|
+
* }
|
|
59
|
+
* })
|
|
60
|
+
* )
|
|
61
|
+
* ```
|
|
62
|
+
*
|
|
11
63
|
* @public
|
|
12
64
|
*/
|
|
13
65
|
export declare const on: {
|
|
@@ -100,18 +152,78 @@ export declare const on: {
|
|
|
100
152
|
waiting: (handler: (event: Event, ctx: DOMContext) => void) => Renderable;
|
|
101
153
|
};
|
|
102
154
|
/**
|
|
103
|
-
* Creates an event handler that emits the value
|
|
155
|
+
* Creates an event handler that extracts and emits the string value from an input element.
|
|
156
|
+
*
|
|
157
|
+
* This utility simplifies handling input events by automatically extracting the value
|
|
158
|
+
* from the target element and passing it to your callback function.
|
|
159
|
+
*
|
|
160
|
+
* @example
|
|
161
|
+
* ```typescript
|
|
162
|
+
* const name = prop('')
|
|
163
|
+
*
|
|
164
|
+
* html.input(
|
|
165
|
+
* attr.value(name),
|
|
166
|
+
* on.input(emitValue(value => name.value = value))
|
|
167
|
+
* )
|
|
168
|
+
* ```
|
|
169
|
+
*
|
|
170
|
+
* @example
|
|
171
|
+
* ```typescript
|
|
172
|
+
* // With textarea
|
|
173
|
+
* const description = prop('')
|
|
174
|
+
*
|
|
175
|
+
* html.textarea(
|
|
176
|
+
* attr.value(description),
|
|
177
|
+
* on.input(emitValue(value => {
|
|
178
|
+
* description.value = value
|
|
179
|
+
* console.log('Description updated:', value)
|
|
180
|
+
* }))
|
|
181
|
+
* )
|
|
182
|
+
* ```
|
|
104
183
|
*
|
|
105
|
-
* @param fn -
|
|
106
|
-
* @returns
|
|
184
|
+
* @param fn - Callback function that receives the input element's string value
|
|
185
|
+
* @returns Event handler function that can be used with event listeners
|
|
107
186
|
* @public
|
|
108
187
|
*/
|
|
109
188
|
export declare const emitValue: (fn: (text: string) => void) => (event: Event) => void;
|
|
110
189
|
/**
|
|
111
|
-
*
|
|
190
|
+
* Creates an event handler that extracts and emits the numeric value from an input element.
|
|
112
191
|
*
|
|
113
|
-
*
|
|
114
|
-
*
|
|
192
|
+
* This utility automatically converts the input's value to a number using the browser's
|
|
193
|
+
* built-in `valueAsNumber` property, which handles number inputs correctly and returns
|
|
194
|
+
* `NaN` for invalid numeric values.
|
|
195
|
+
*
|
|
196
|
+
* @example
|
|
197
|
+
* ```typescript
|
|
198
|
+
* const age = prop(0)
|
|
199
|
+
*
|
|
200
|
+
* html.input(
|
|
201
|
+
* attr.type('number'),
|
|
202
|
+
* attr.value(age.map(String)),
|
|
203
|
+
* on.input(emitValueAsNumber(value => {
|
|
204
|
+
* if (!isNaN(value)) {
|
|
205
|
+
* age.value = value
|
|
206
|
+
* }
|
|
207
|
+
* }))
|
|
208
|
+
* )
|
|
209
|
+
* ```
|
|
210
|
+
*
|
|
211
|
+
* @example
|
|
212
|
+
* ```typescript
|
|
213
|
+
* // With range input
|
|
214
|
+
* const volume = prop(50)
|
|
215
|
+
*
|
|
216
|
+
* html.input(
|
|
217
|
+
* attr.type('range'),
|
|
218
|
+
* attr.min('0'),
|
|
219
|
+
* attr.max('100'),
|
|
220
|
+
* attr.value(volume.map(String)),
|
|
221
|
+
* on.input(emitValueAsNumber(value => volume.value = value))
|
|
222
|
+
* )
|
|
223
|
+
* ```
|
|
224
|
+
*
|
|
225
|
+
* @param fn - Callback function that receives the input element's numeric value (may be NaN)
|
|
226
|
+
* @returns Event handler function that can be used with event listeners
|
|
115
227
|
* @public
|
|
116
228
|
*/
|
|
117
229
|
export declare const emitValueAsNumber: (fn: (num: number) => void) => (event: Event) => void;
|
|
@@ -144,9 +256,55 @@ export declare const emitValueAsDateTime: (fn: (date: Date) => void) => (event:
|
|
|
144
256
|
*/
|
|
145
257
|
export declare const emitValueAsNullableDateTime: (fn: (date: Date | null) => void) => (event: Event) => void;
|
|
146
258
|
/**
|
|
147
|
-
*
|
|
148
|
-
*
|
|
149
|
-
*
|
|
259
|
+
* Creates an event handler that extracts and emits the checked state from a checkbox or radio input.
|
|
260
|
+
*
|
|
261
|
+
* This utility simplifies handling checkbox and radio button state changes by automatically
|
|
262
|
+
* extracting the `checked` property from the target element.
|
|
263
|
+
*
|
|
264
|
+
* @example
|
|
265
|
+
* ```typescript
|
|
266
|
+
* const isEnabled = prop(false)
|
|
267
|
+
*
|
|
268
|
+
* html.input(
|
|
269
|
+
* attr.type('checkbox'),
|
|
270
|
+
* attr.checked(isEnabled),
|
|
271
|
+
* on.change(emitChecked(checked => isEnabled.value = checked))
|
|
272
|
+
* )
|
|
273
|
+
* ```
|
|
274
|
+
*
|
|
275
|
+
* @example
|
|
276
|
+
* ```typescript
|
|
277
|
+
* // With radio buttons
|
|
278
|
+
* const selectedOption = prop('')
|
|
279
|
+
*
|
|
280
|
+
* html.div(
|
|
281
|
+
* html.label(
|
|
282
|
+
* html.input(
|
|
283
|
+
* attr.type('radio'),
|
|
284
|
+
* attr.name('option'),
|
|
285
|
+
* attr.value('A'),
|
|
286
|
+
* on.change(emitChecked(checked => {
|
|
287
|
+
* if (checked) selectedOption.value = 'A'
|
|
288
|
+
* }))
|
|
289
|
+
* ),
|
|
290
|
+
* 'Option A'
|
|
291
|
+
* ),
|
|
292
|
+
* html.label(
|
|
293
|
+
* html.input(
|
|
294
|
+
* attr.type('radio'),
|
|
295
|
+
* attr.name('option'),
|
|
296
|
+
* attr.value('B'),
|
|
297
|
+
* on.change(emitChecked(checked => {
|
|
298
|
+
* if (checked) selectedOption.value = 'B'
|
|
299
|
+
* }))
|
|
300
|
+
* ),
|
|
301
|
+
* 'Option B'
|
|
302
|
+
* )
|
|
303
|
+
* )
|
|
304
|
+
* ```
|
|
305
|
+
*
|
|
306
|
+
* @param fn - Callback function that receives the input element's checked state
|
|
307
|
+
* @returns Event handler function that can be used with event listeners
|
|
150
308
|
* @public
|
|
151
309
|
*/
|
|
152
310
|
export declare const emitChecked: (fn: (checked: boolean) => void) => (event: Event) => void;
|
package/renderable/provider.d.ts
CHANGED
|
@@ -40,26 +40,196 @@ export type ProviderOptions = {
|
|
|
40
40
|
* @returns A Clear function that can be used to clean up any resources associated with the execution.
|
|
41
41
|
* @public
|
|
42
42
|
*/
|
|
43
|
-
export declare const WithProvider: (fn: (
|
|
43
|
+
export declare const WithProvider: (fn: (opts: ProviderOptions) => TNode | void) => Renderable;
|
|
44
44
|
/**
|
|
45
|
-
*
|
|
45
|
+
* Makes a provider available to all child components in the component tree.
|
|
46
46
|
*
|
|
47
|
-
*
|
|
48
|
-
*
|
|
49
|
-
*
|
|
47
|
+
* This function creates a provider context that child components can access using `Use`.
|
|
48
|
+
* The provider is automatically disposed when the component is unmounted.
|
|
49
|
+
*
|
|
50
|
+
* @example
|
|
51
|
+
* ```typescript
|
|
52
|
+
* // Create a theme provider
|
|
53
|
+
* const ThemeProvider: Provider<Signal<string>> = {
|
|
54
|
+
* mark: makeProviderMark<Signal<string>>('Theme'),
|
|
55
|
+
* create: () => {
|
|
56
|
+
* const theme = prop('light')
|
|
57
|
+
* return {
|
|
58
|
+
* value: theme,
|
|
59
|
+
* dispose: () => theme.dispose()
|
|
60
|
+
* }
|
|
61
|
+
* }
|
|
62
|
+
* }
|
|
63
|
+
*
|
|
64
|
+
* // Provide the theme to child components
|
|
65
|
+
* const App = () =>
|
|
66
|
+
* Provide(
|
|
67
|
+
* ThemeProvider,
|
|
68
|
+
* {}, // options
|
|
69
|
+
* () => html.div(
|
|
70
|
+
* html.h1('My App'),
|
|
71
|
+
* ThemeToggle(), // Can access the theme
|
|
72
|
+
* MainContent() // Can also access the theme
|
|
73
|
+
* )
|
|
74
|
+
* )
|
|
75
|
+
* ```
|
|
76
|
+
*
|
|
77
|
+
* @example
|
|
78
|
+
* ```typescript
|
|
79
|
+
* // Provider with options
|
|
80
|
+
* const ConfigProvider: Provider<Config, { apiUrl: string }> = {
|
|
81
|
+
* mark: makeProviderMark<Config>('Config'),
|
|
82
|
+
* create: (options) => {
|
|
83
|
+
* const config = new Config(options.apiUrl)
|
|
84
|
+
* return {
|
|
85
|
+
* value: config,
|
|
86
|
+
* dispose: () => config.cleanup()
|
|
87
|
+
* }
|
|
88
|
+
* }
|
|
89
|
+
* }
|
|
90
|
+
*
|
|
91
|
+
* // Provide with specific options
|
|
92
|
+
* Provide(
|
|
93
|
+
* ConfigProvider,
|
|
94
|
+
* { apiUrl: 'https://api.example.com' },
|
|
95
|
+
* () => AppContent()
|
|
96
|
+
* )
|
|
97
|
+
* ```
|
|
98
|
+
*
|
|
99
|
+
* @template T - The type of value provided by the provider
|
|
100
|
+
* @template O - The type of options passed to the provider
|
|
101
|
+
* @param provider - The provider definition containing mark and create function
|
|
102
|
+
* @param options - Options to pass to the provider's create function
|
|
103
|
+
* @param child - Function that returns the child components that can access the provider
|
|
104
|
+
* @returns A renderable that provides the value to its children
|
|
105
|
+
* @public
|
|
50
106
|
*/
|
|
51
107
|
export declare const Provide: <T, O>(provider: Provider<T, O>, options: O, child: () => TNode) => Renderable;
|
|
52
108
|
/**
|
|
53
|
-
*
|
|
109
|
+
* Consumes a provider value and makes it available to a child component.
|
|
110
|
+
*
|
|
111
|
+
* This function looks up a provider in the component tree and passes its value
|
|
112
|
+
* to the child function. The provider must have been made available by a parent
|
|
113
|
+
* component using `Provide`.
|
|
114
|
+
*
|
|
115
|
+
* @example
|
|
116
|
+
* ```typescript
|
|
117
|
+
* // Use a theme provider
|
|
118
|
+
* const ThemeToggle = () =>
|
|
119
|
+
* Use(
|
|
120
|
+
* ThemeProvider,
|
|
121
|
+
* (theme) => html.button(
|
|
122
|
+
* on.click(() => {
|
|
123
|
+
* theme.value = theme.value === 'light' ? 'dark' : 'light'
|
|
124
|
+
* }),
|
|
125
|
+
* 'Current theme: ', theme
|
|
126
|
+
* )
|
|
127
|
+
* )
|
|
128
|
+
* ```
|
|
54
129
|
*
|
|
55
|
-
* @
|
|
56
|
-
*
|
|
130
|
+
* @example
|
|
131
|
+
* ```typescript
|
|
132
|
+
* // Use multiple properties from a provider
|
|
133
|
+
* const UserProfile = () =>
|
|
134
|
+
* Use(
|
|
135
|
+
* UserProvider,
|
|
136
|
+
* (user) => html.div(
|
|
137
|
+
* html.h2('Welcome, ', user.map(u => u.name)),
|
|
138
|
+
* html.p('Email: ', user.map(u => u.email)),
|
|
139
|
+
* html.p('Role: ', user.map(u => u.role))
|
|
140
|
+
* )
|
|
141
|
+
* )
|
|
142
|
+
* ```
|
|
143
|
+
*
|
|
144
|
+
* @example
|
|
145
|
+
* ```typescript
|
|
146
|
+
* // Use provider in conditional rendering
|
|
147
|
+
* const ConditionalContent = () =>
|
|
148
|
+
* Use(
|
|
149
|
+
* AuthProvider,
|
|
150
|
+
* (auth) => auth.map(a => a.isLoggedIn)
|
|
151
|
+
* ? html.div('Welcome back!')
|
|
152
|
+
* : html.div('Please log in')
|
|
153
|
+
* )
|
|
154
|
+
* ```
|
|
155
|
+
*
|
|
156
|
+
* @template T - The type of value provided by the provider
|
|
157
|
+
* @param provider - The provider to consume (must be available in parent components)
|
|
158
|
+
* @param child - Function that receives the provider value and returns content to render
|
|
159
|
+
* @returns A renderable that consumes the provider and renders the child content
|
|
160
|
+
* @throws {ProviderNotFoundError} When the provider is not found in the component tree
|
|
161
|
+
* @public
|
|
57
162
|
*/
|
|
58
163
|
export declare const Use: <T>(provider: Provider<T>, child: (provider: T) => TNode) => Renderable;
|
|
59
164
|
/**
|
|
60
|
-
*
|
|
165
|
+
* Consumes multiple providers and makes their values available to a child component.
|
|
166
|
+
*
|
|
167
|
+
* This function is a convenience wrapper for consuming multiple providers at once.
|
|
168
|
+
* It's equivalent to nesting multiple `Use` calls but provides a cleaner API when
|
|
169
|
+
* you need access to several providers simultaneously.
|
|
61
170
|
*
|
|
62
|
-
* @
|
|
63
|
-
*
|
|
171
|
+
* @example
|
|
172
|
+
* ```typescript
|
|
173
|
+
* // Use multiple providers together
|
|
174
|
+
* const Dashboard = () =>
|
|
175
|
+
* UseMany(
|
|
176
|
+
* UserProvider,
|
|
177
|
+
* ThemeProvider,
|
|
178
|
+
* ConfigProvider
|
|
179
|
+
* )(
|
|
180
|
+
* (user, theme, config) => html.div(
|
|
181
|
+
* attr.class(theme.map(t => `theme-${t}`)),
|
|
182
|
+
* html.h1('Dashboard for ', user.map(u => u.name)),
|
|
183
|
+
* html.p('API URL: ', config.map(c => c.apiUrl)),
|
|
184
|
+
* html.p('Current theme: ', theme)
|
|
185
|
+
* )
|
|
186
|
+
* )
|
|
187
|
+
* ```
|
|
188
|
+
*
|
|
189
|
+
* @example
|
|
190
|
+
* ```typescript
|
|
191
|
+
* // Equivalent to nested Use calls
|
|
192
|
+
* const Dashboard = () =>
|
|
193
|
+
* Use(UserProvider, user =>
|
|
194
|
+
* Use(ThemeProvider, theme =>
|
|
195
|
+
* Use(ConfigProvider, config =>
|
|
196
|
+
* html.div(
|
|
197
|
+
* // Same content as above
|
|
198
|
+
* )
|
|
199
|
+
* )
|
|
200
|
+
* )
|
|
201
|
+
* )
|
|
202
|
+
* ```
|
|
203
|
+
*
|
|
204
|
+
* @example
|
|
205
|
+
* ```typescript
|
|
206
|
+
* // Type-safe access to multiple providers
|
|
207
|
+
* const SettingsPanel = () =>
|
|
208
|
+
* UseMany(
|
|
209
|
+
* PreferencesProvider,
|
|
210
|
+
* UserProvider
|
|
211
|
+
* )(
|
|
212
|
+
* (preferences, user) => html.div(
|
|
213
|
+
* html.h2('Settings for ', user.map(u => u.name)),
|
|
214
|
+
* html.label(
|
|
215
|
+
* 'Theme: ',
|
|
216
|
+
* html.select(
|
|
217
|
+
* attr.value(preferences.map(p => p.theme)),
|
|
218
|
+
* on.change(emitValue(value => {
|
|
219
|
+
* preferences.update(p => ({ ...p, theme: value }))
|
|
220
|
+
* })),
|
|
221
|
+
* html.option(attr.value('light'), 'Light'),
|
|
222
|
+
* html.option(attr.value('dark'), 'Dark')
|
|
223
|
+
* )
|
|
224
|
+
* )
|
|
225
|
+
* )
|
|
226
|
+
* )
|
|
227
|
+
* ```
|
|
228
|
+
*
|
|
229
|
+
* @template T - Tuple type representing the types of all providers
|
|
230
|
+
* @param providers - Variable number of providers to consume
|
|
231
|
+
* @returns Function that takes a child function and returns a renderable
|
|
232
|
+
* @throws {ProviderNotFoundError} When any of the providers is not found in the component tree
|
|
233
|
+
* @public
|
|
64
234
|
*/
|
|
65
235
|
export declare const UseMany: <T extends Provider<unknown>[]>(...providers: T) => (child: (...values: ToProviderTypes<T>) => TNode) => Renderable;
|
package/renderable/repeat.d.ts
CHANGED
|
@@ -2,12 +2,70 @@ import { ElementPosition } from '../std/element-position';
|
|
|
2
2
|
import { Value } from '../std/value';
|
|
3
3
|
import { TNode, Renderable } from '../types/domain';
|
|
4
4
|
/**
|
|
5
|
-
*
|
|
5
|
+
* Renders content a specified number of times, with each iteration receiving position information.
|
|
6
6
|
*
|
|
7
|
-
*
|
|
8
|
-
*
|
|
9
|
-
*
|
|
10
|
-
*
|
|
7
|
+
* This function is useful for generating repeated UI elements based on a count rather than an array.
|
|
8
|
+
* Each iteration receives an `ElementPosition` object that provides the current index and position
|
|
9
|
+
* information relative to the total count.
|
|
10
|
+
*
|
|
11
|
+
* @example
|
|
12
|
+
* ```typescript
|
|
13
|
+
* // Create a simple numbered list
|
|
14
|
+
* const count = prop(5)
|
|
15
|
+
*
|
|
16
|
+
* Repeat(count,
|
|
17
|
+
* (position) => html.div(
|
|
18
|
+
* `Item ${position.index + 1} of ${position.total.value}`,
|
|
19
|
+
* position.isFirst ? ' (first)' : '',
|
|
20
|
+
* position.isLast ? ' (last)' : ''
|
|
21
|
+
* )
|
|
22
|
+
* )
|
|
23
|
+
* ```
|
|
24
|
+
*
|
|
25
|
+
* @example
|
|
26
|
+
* ```typescript
|
|
27
|
+
* // Create a star rating component
|
|
28
|
+
* const rating = prop(3)
|
|
29
|
+
* const maxStars = 5
|
|
30
|
+
*
|
|
31
|
+
* Repeat(maxStars,
|
|
32
|
+
* (position) => html.span(
|
|
33
|
+
* attr.class(position.index < rating.value ? 'star-filled' : 'star-empty'),
|
|
34
|
+
* '★'
|
|
35
|
+
* )
|
|
36
|
+
* )
|
|
37
|
+
* ```
|
|
38
|
+
*
|
|
39
|
+
* @example
|
|
40
|
+
* ```typescript
|
|
41
|
+
* // With separators between items
|
|
42
|
+
* Repeat(3,
|
|
43
|
+
* (position) => html.span(`Item ${position.index}`),
|
|
44
|
+
* () => html.span(' | ') // Separator
|
|
45
|
+
* )
|
|
46
|
+
* // Renders: Item 0 | Item 1 | Item 2
|
|
47
|
+
* ```
|
|
48
|
+
*
|
|
49
|
+
* @example
|
|
50
|
+
* ```typescript
|
|
51
|
+
* // Dynamic count that updates the UI
|
|
52
|
+
* const itemCount = prop(2)
|
|
53
|
+
*
|
|
54
|
+
* html.div(
|
|
55
|
+
* html.button(
|
|
56
|
+
* on.click(() => itemCount.value++),
|
|
57
|
+
* 'Add Item'
|
|
58
|
+
* ),
|
|
59
|
+
* Repeat(itemCount,
|
|
60
|
+
* (position) => html.div(`Dynamic item ${position.index + 1}`)
|
|
61
|
+
* )
|
|
62
|
+
* )
|
|
63
|
+
* ```
|
|
64
|
+
*
|
|
65
|
+
* @param times - A signal or number representing how many times to repeat the content
|
|
66
|
+
* @param element - Function that returns content for each iteration, receives position information
|
|
67
|
+
* @param separator - Optional function that returns content to place between iterations
|
|
68
|
+
* @returns A renderable that displays the repeated content
|
|
11
69
|
* @public
|
|
12
70
|
*/
|
|
13
71
|
export declare const Repeat: (times: Value<number>, element: (index: ElementPosition) => TNode, separator?: (pos: ElementPosition) => TNode) => Renderable;
|