@proyecto-viviana/solid-stately 0.0.1 → 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.
@@ -0,0 +1,193 @@
1
+ /**
2
+ * Checkbox group state for Solid Stately
3
+ *
4
+ * Provides state management for a checkbox group component.
5
+ * Provides a name for the group, and manages selection and focus state.
6
+ *
7
+ * This is a 1:1 port of @react-stately/checkbox's useCheckboxGroupState.
8
+ */
9
+
10
+ import { createSignal, Accessor } from 'solid-js';
11
+ import { type MaybeAccessor, access } from '../utils';
12
+
13
+ // ============================================
14
+ // TYPES
15
+ // ============================================
16
+
17
+ export interface CheckboxGroupProps {
18
+ /** The current selected values (controlled). */
19
+ value?: string[];
20
+ /** The default selected values (uncontrolled). */
21
+ defaultValue?: string[];
22
+ /** Handler that is called when the value changes. */
23
+ onChange?: (value: string[]) => void;
24
+ /** Whether the checkbox group is disabled. */
25
+ isDisabled?: boolean;
26
+ /** Whether the checkbox group is read only. */
27
+ isReadOnly?: boolean;
28
+ /** Whether the checkbox group is required. */
29
+ isRequired?: boolean;
30
+ /** Whether the checkbox group is invalid. */
31
+ isInvalid?: boolean;
32
+ /** The name of the checkbox group, used when submitting an HTML form. */
33
+ name?: string;
34
+ /** The form to associate the checkbox group with. */
35
+ form?: string;
36
+ /** The label for the checkbox group. */
37
+ label?: string;
38
+ /** Handler that is called when the checkbox group receives focus. */
39
+ onFocus?: (e: FocusEvent) => void;
40
+ /** Handler that is called when the checkbox group loses focus. */
41
+ onBlur?: (e: FocusEvent) => void;
42
+ /** Handler that is called when the checkbox group's focus status changes. */
43
+ onFocusChange?: (isFocused: boolean) => void;
44
+ }
45
+
46
+ export interface CheckboxGroupState {
47
+ /** Current selected values. */
48
+ readonly value: Accessor<readonly string[]>;
49
+ /** Default selected values. */
50
+ readonly defaultValue: readonly string[];
51
+ /** Whether the checkbox group is disabled. */
52
+ readonly isDisabled: boolean;
53
+ /** Whether the checkbox group is read only. */
54
+ readonly isReadOnly: boolean;
55
+ /** Whether the checkbox group is invalid. */
56
+ readonly isInvalid: boolean;
57
+ /**
58
+ * Whether the checkboxes in the group are required.
59
+ * This changes to false once at least one item is selected.
60
+ */
61
+ readonly isRequired: Accessor<boolean>;
62
+ /** Returns whether the given value is selected. */
63
+ isSelected(value: string): boolean;
64
+ /** Sets the selected values. */
65
+ setValue(value: string[]): void;
66
+ /** Adds a value to the set of selected values. */
67
+ addValue(value: string): void;
68
+ /** Removes a value from the set of selected values. */
69
+ removeValue(value: string): void;
70
+ /** Toggles a value in the set of selected values. */
71
+ toggleValue(value: string): void;
72
+ }
73
+
74
+ // ============================================
75
+ // IMPLEMENTATION
76
+ // ============================================
77
+
78
+ /**
79
+ * Provides state management for a checkbox group component.
80
+ * Provides a name for the group, and manages selection and focus state.
81
+ */
82
+ export function createCheckboxGroupState(
83
+ props: MaybeAccessor<CheckboxGroupProps> = {}
84
+ ): CheckboxGroupState {
85
+ const getProps = () => access(props);
86
+
87
+ // Get initial values
88
+ const initialProps = getProps();
89
+ const initialValue = initialProps.value ?? initialProps.defaultValue ?? [];
90
+
91
+ // Create internal signal for uncontrolled mode
92
+ const [internalValue, setInternalValue] = createSignal<readonly string[]>(initialValue);
93
+
94
+ // Determine if controlled
95
+ const isControlled = () => getProps().value !== undefined;
96
+
97
+ // Get current value
98
+ const value: Accessor<readonly string[]> = () => {
99
+ const p = getProps();
100
+ return isControlled() ? (p.value ?? []) : internalValue();
101
+ };
102
+
103
+ // Check if required (true if isRequired and no items selected)
104
+ const isRequired: Accessor<boolean> = () => {
105
+ const p = getProps();
106
+ return !!p.isRequired && value().length === 0;
107
+ };
108
+
109
+ // Check if invalid
110
+ const isInvalid = () => {
111
+ return getProps().isInvalid ?? false;
112
+ };
113
+
114
+ // Set value
115
+ function setValue(newValue: string[]): void {
116
+ const p = getProps();
117
+ if (p.isReadOnly || p.isDisabled) {
118
+ return;
119
+ }
120
+
121
+ if (!isControlled()) {
122
+ setInternalValue(newValue);
123
+ }
124
+
125
+ p.onChange?.(newValue);
126
+ }
127
+
128
+ // Check if value is selected
129
+ function isSelected(checkValue: string): boolean {
130
+ return value().includes(checkValue);
131
+ }
132
+
133
+ // Add value
134
+ function addValue(addVal: string): void {
135
+ const p = getProps();
136
+ if (p.isReadOnly || p.isDisabled) {
137
+ return;
138
+ }
139
+
140
+ const current = value();
141
+ if (!current.includes(addVal)) {
142
+ setValue([...current, addVal]);
143
+ }
144
+ }
145
+
146
+ // Remove value
147
+ function removeValue(removeVal: string): void {
148
+ const p = getProps();
149
+ if (p.isReadOnly || p.isDisabled) {
150
+ return;
151
+ }
152
+
153
+ const current = value();
154
+ if (current.includes(removeVal)) {
155
+ setValue(current.filter((v) => v !== removeVal));
156
+ }
157
+ }
158
+
159
+ // Toggle value
160
+ function toggleValue(toggleVal: string): void {
161
+ const p = getProps();
162
+ if (p.isReadOnly || p.isDisabled) {
163
+ return;
164
+ }
165
+
166
+ const current = value();
167
+ if (current.includes(toggleVal)) {
168
+ setValue(current.filter((v) => v !== toggleVal));
169
+ } else {
170
+ setValue([...current, toggleVal]);
171
+ }
172
+ }
173
+
174
+ return {
175
+ value,
176
+ defaultValue: initialProps.defaultValue ?? initialValue,
177
+ get isDisabled() {
178
+ return getProps().isDisabled ?? false;
179
+ },
180
+ get isReadOnly() {
181
+ return getProps().isReadOnly ?? false;
182
+ },
183
+ get isInvalid() {
184
+ return isInvalid();
185
+ },
186
+ isRequired,
187
+ isSelected,
188
+ setValue,
189
+ addValue,
190
+ removeValue,
191
+ toggleValue,
192
+ };
193
+ }
@@ -0,0 +1,5 @@
1
+ export {
2
+ createCheckboxGroupState,
3
+ type CheckboxGroupProps,
4
+ type CheckboxGroupState,
5
+ } from './createCheckboxGroupState';
package/src/index.ts ADDED
@@ -0,0 +1,34 @@
1
+ // Toggle
2
+ export {
3
+ createToggleState,
4
+ type ToggleStateOptions,
5
+ type ToggleState,
6
+ } from './toggle';
7
+
8
+ // TextField
9
+ export {
10
+ createTextFieldState,
11
+ type TextFieldStateOptions,
12
+ type TextFieldState,
13
+ } from './textfield';
14
+
15
+ // Checkbox
16
+ export {
17
+ createCheckboxGroupState,
18
+ type CheckboxGroupProps,
19
+ type CheckboxGroupState,
20
+ } from './checkbox';
21
+
22
+ // Radio
23
+ export {
24
+ createRadioGroupState,
25
+ radioGroupSyncVersion,
26
+ type RadioGroupProps,
27
+ type RadioGroupState,
28
+ } from './radio';
29
+
30
+ // SSR
31
+ export { createIsSSR, createId, canUseDOM } from './ssr';
32
+
33
+ // Utils
34
+ export { access, isAccessor, type MaybeAccessor, type MaybeAccessorValue } from './utils';
@@ -0,0 +1,201 @@
1
+ /**
2
+ * Radio group state for Solid Stately
3
+ *
4
+ * Provides state management for a radio group component.
5
+ * Provides a name for the group, and manages selection and focus state.
6
+ *
7
+ * This is a 1:1 port of @react-stately/radio's useRadioGroupState.
8
+ */
9
+
10
+ import { createSignal, Accessor, untrack } from 'solid-js';
11
+ import { type MaybeAccessor, access } from '../utils';
12
+ import { createId } from '../ssr';
13
+
14
+ // ============================================
15
+ // TYPES
16
+ // ============================================
17
+
18
+ export interface RadioGroupProps {
19
+ /** The current selected value (controlled). */
20
+ value?: string | null;
21
+ /** The default selected value (uncontrolled). */
22
+ defaultValue?: string | null;
23
+ /** Handler that is called when the value changes. */
24
+ onChange?: (value: string) => void;
25
+ /** Whether the radio group is disabled. */
26
+ isDisabled?: boolean;
27
+ /** Whether the radio group is read only. */
28
+ isReadOnly?: boolean;
29
+ /** Whether the radio group is required. */
30
+ isRequired?: boolean;
31
+ /** Whether the radio group is invalid. */
32
+ isInvalid?: boolean;
33
+ /** The name of the radio group, used when submitting an HTML form. */
34
+ name?: string;
35
+ /** The form to associate the radio group with. */
36
+ form?: string;
37
+ /** The label for the radio group. */
38
+ label?: string;
39
+ /** Orientation of the radio group. */
40
+ orientation?: 'horizontal' | 'vertical';
41
+ /** Handler that is called when the radio group receives focus. */
42
+ onFocus?: (e: FocusEvent) => void;
43
+ /** Handler that is called when the radio group loses focus. */
44
+ onBlur?: (e: FocusEvent) => void;
45
+ /** Handler that is called when the radio group's focus status changes. */
46
+ onFocusChange?: (isFocused: boolean) => void;
47
+ }
48
+
49
+ export interface RadioGroupState {
50
+ /** The name for the group, used for native form submission. */
51
+ readonly name: string;
52
+
53
+ /** Whether the radio group is disabled. */
54
+ readonly isDisabled: boolean;
55
+
56
+ /** Whether the radio group is read only. */
57
+ readonly isReadOnly: boolean;
58
+
59
+ /** Whether the radio group is required. */
60
+ readonly isRequired: boolean;
61
+
62
+ /** Whether the radio group is invalid. */
63
+ readonly isInvalid: boolean;
64
+
65
+ /** The currently selected value. */
66
+ readonly selectedValue: Accessor<string | null>;
67
+
68
+ /** The default selected value. */
69
+ readonly defaultSelectedValue: string | null;
70
+
71
+ /** Sets the selected value. */
72
+ setSelectedValue(value: string | null): void;
73
+
74
+ /** The value of the last focused radio. */
75
+ readonly lastFocusedValue: Accessor<string | null>;
76
+
77
+ /** Sets the last focused value. */
78
+ setLastFocusedValue(value: string | null): void;
79
+ }
80
+
81
+ // ============================================
82
+ // INTERNAL: SolidJS-specific sync mechanism
83
+ // ============================================
84
+
85
+ /**
86
+ * Internal WeakMap to store sync version accessors for each radio group state.
87
+ * This is used by createRadio to trigger DOM sync when native radio behavior
88
+ * causes the DOM checked state to desync from our reactive state.
89
+ *
90
+ * This is kept separate from RadioGroupState to maintain API parity with React-Stately.
91
+ * @internal
92
+ */
93
+ export const radioGroupSyncVersion: WeakMap<RadioGroupState, Accessor<number>> = new WeakMap();
94
+
95
+ // ============================================
96
+ // IMPLEMENTATION
97
+ // ============================================
98
+
99
+ /**
100
+ * Provides state management for a radio group component.
101
+ * Provides a name for the group, and manages selection and focus state.
102
+ */
103
+ export function createRadioGroupState(
104
+ props: MaybeAccessor<RadioGroupProps> = {}
105
+ ): RadioGroupState {
106
+ const getProps = () => access(props);
107
+
108
+ // Get initial props using untrack to avoid setting up dependencies
109
+ // This ensures we capture the initial defaultValue without reactivity issues
110
+ const initialProps = untrack(() => getProps());
111
+
112
+ // Generate name - preserved for backward compatibility
113
+ // React Aria now generates the name instead of stately
114
+ const name = initialProps.name || `radio-group-${createId()}`;
115
+
116
+ // Create internal signal for uncontrolled mode
117
+ // Initialize with defaultValue only (not value, which is for controlled mode)
118
+ const [internalValue, setInternalValue] = createSignal<string | null>(
119
+ initialProps.defaultValue ?? null
120
+ );
121
+ const [lastFocusedValue, setLastFocusedValueInternal] = createSignal<string | null>(null);
122
+
123
+ // SolidJS-specific: Version counter for triggering DOM sync across all radios
124
+ // This handles the case where native radio behavior causes DOM state to desync
125
+ // from our reactive state (e.g., clicking a radio unchecks siblings in the DOM)
126
+ const [syncVersion, setSyncVersion] = createSignal(0);
127
+
128
+ // Determine if controlled - must be reactive to handle dynamic props
129
+ const isControlled = () => getProps().value !== undefined;
130
+
131
+ // Get current value - reactive for both controlled and uncontrolled modes
132
+ const selectedValue: Accessor<string | null> = () => {
133
+ const p = getProps();
134
+ // In controlled mode, always read from props.value reactively
135
+ // In uncontrolled mode, read from internal signal
136
+ if (p.value !== undefined) {
137
+ return p.value ?? null;
138
+ }
139
+ return internalValue();
140
+ };
141
+
142
+ // Check if invalid
143
+ const isInvalid = () => {
144
+ return getProps().isInvalid ?? false;
145
+ };
146
+
147
+ // Set value
148
+ function setSelectedValue(value: string | null): void {
149
+ const p = getProps();
150
+ if (p.isReadOnly || p.isDisabled) {
151
+ return;
152
+ }
153
+
154
+ // Always increment syncVersion to trigger DOM sync across all radios
155
+ // This is crucial for SolidJS because:
156
+ // 1. Native radio behavior unchecks siblings when one is checked
157
+ // 2. In controlled mode, isSelected() may not change even though DOM changed
158
+ // 3. We need ALL radios to re-sync their checked state after any click
159
+ setSyncVersion((v) => v + 1);
160
+
161
+ if (!isControlled()) {
162
+ setInternalValue(value);
163
+ }
164
+
165
+ if (value != null) {
166
+ p.onChange?.(value);
167
+ }
168
+ }
169
+
170
+ // Set last focused value
171
+ function setLastFocusedValue(value: string | null): void {
172
+ setLastFocusedValueInternal(value);
173
+ }
174
+
175
+ const state: RadioGroupState = {
176
+ name,
177
+ selectedValue,
178
+ defaultSelectedValue: initialProps.defaultValue ?? null,
179
+ setSelectedValue,
180
+ lastFocusedValue,
181
+ setLastFocusedValue,
182
+ get isDisabled() {
183
+ return getProps().isDisabled ?? false;
184
+ },
185
+ get isReadOnly() {
186
+ return getProps().isReadOnly ?? false;
187
+ },
188
+ get isRequired() {
189
+ return getProps().isRequired ?? false;
190
+ },
191
+ get isInvalid() {
192
+ return isInvalid();
193
+ },
194
+ };
195
+
196
+ // Store syncVersion in internal WeakMap (not part of public API)
197
+ // This maintains API parity with React-Stately while supporting SolidJS's reactivity needs
198
+ radioGroupSyncVersion.set(state, syncVersion);
199
+
200
+ return state;
201
+ }
@@ -0,0 +1,6 @@
1
+ export {
2
+ createRadioGroupState,
3
+ radioGroupSyncVersion,
4
+ type RadioGroupProps,
5
+ type RadioGroupState,
6
+ } from './createRadioGroupState';
@@ -4,20 +4,33 @@
4
4
  * SolidJS has built-in SSR support with `isServer` and `createUniqueId()`.
5
5
  * These utilities provide a consistent API matching React-Stately's patterns.
6
6
  */
7
+
8
+ import { createUniqueId } from 'solid-js';
9
+ import { isServer } from 'solid-js/web';
10
+
7
11
  /**
8
12
  * Returns whether the component is currently being server side rendered.
9
13
  * Can be used to delay browser-specific rendering until after hydration.
10
14
  */
11
- export declare function createIsSSR(): boolean;
15
+ export function createIsSSR(): boolean {
16
+ return isServer;
17
+ }
18
+
12
19
  /**
13
20
  * Generate a unique ID that is stable across server and client.
14
21
  * Uses SolidJS's built-in createUniqueId which handles SSR correctly.
15
22
  *
16
23
  * @param defaultId - Optional default ID to use instead of generating one.
17
24
  */
18
- export declare function createId(defaultId?: string): string;
25
+ export function createId(defaultId?: string): string {
26
+ if (defaultId) {
27
+ return defaultId;
28
+ }
29
+ return `solid-stately-${createUniqueId()}`;
30
+ }
31
+
19
32
  /**
20
33
  * Check if we can use DOM APIs.
21
34
  * This is useful for code that needs to run only in the browser.
22
35
  */
23
- export declare const canUseDOM: boolean;
36
+ export const canUseDOM = !isServer;
@@ -0,0 +1,75 @@
1
+ /**
2
+ * TextField state for Solid Stately
3
+ *
4
+ * Provides state management for text input components.
5
+ *
6
+ * This is a port of @react-stately/utils's useControlledState pattern
7
+ * as used by @react-aria/textfield.
8
+ */
9
+
10
+ import { createSignal, Accessor } from 'solid-js';
11
+ import { type MaybeAccessor, access } from '../utils';
12
+
13
+ // ============================================
14
+ // TYPES
15
+ // ============================================
16
+
17
+ export interface TextFieldStateOptions {
18
+ /** The current value (controlled). */
19
+ value?: string;
20
+ /** The default value (uncontrolled). */
21
+ defaultValue?: string;
22
+ /** Handler that is called when the value changes. */
23
+ onChange?: (value: string) => void;
24
+ }
25
+
26
+ export interface TextFieldState {
27
+ /** The current value of the text field. */
28
+ readonly value: Accessor<string>;
29
+ /** Sets the value of the text field. */
30
+ setValue(value: string): void;
31
+ }
32
+
33
+ // ============================================
34
+ // IMPLEMENTATION
35
+ // ============================================
36
+
37
+ /**
38
+ * Provides state management for text input components.
39
+ * Supports both controlled and uncontrolled modes.
40
+ */
41
+ export function createTextFieldState(props: MaybeAccessor<TextFieldStateOptions> = {}): TextFieldState {
42
+ const getProps = () => access(props);
43
+
44
+ // Get initial value
45
+ const initialProps = getProps();
46
+ const initialValue = initialProps.value ?? initialProps.defaultValue ?? '';
47
+
48
+ // Create internal signal for uncontrolled mode
49
+ const [internalValue, setInternalValue] = createSignal(initialValue);
50
+
51
+ // Determine if controlled
52
+ const isControlled = () => getProps().value !== undefined;
53
+
54
+ // Get current value
55
+ const value: Accessor<string> = () => {
56
+ const p = getProps();
57
+ return isControlled() ? (p.value ?? '') : internalValue();
58
+ };
59
+
60
+ // Update value
61
+ function setValue(newValue: string): void {
62
+ const p = getProps();
63
+
64
+ if (!isControlled()) {
65
+ setInternalValue(newValue);
66
+ }
67
+
68
+ p.onChange?.(newValue);
69
+ }
70
+
71
+ return {
72
+ value,
73
+ setValue,
74
+ };
75
+ }
@@ -0,0 +1,5 @@
1
+ export {
2
+ createTextFieldState,
3
+ type TextFieldStateOptions,
4
+ type TextFieldState,
5
+ } from './createTextFieldState';
@@ -0,0 +1,94 @@
1
+ /**
2
+ * Toggle state for Solid Stately
3
+ *
4
+ * Provides state management for toggle components like checkboxes and switches.
5
+ *
6
+ * This is a 1:1 port of @react-stately/toggle's useToggleState.
7
+ */
8
+
9
+ import { createSignal, Accessor } from 'solid-js';
10
+ import { type MaybeAccessor, access } from '../utils';
11
+
12
+ // ============================================
13
+ // TYPES
14
+ // ============================================
15
+
16
+ export interface ToggleStateOptions {
17
+ /** Whether the element should be selected (controlled). */
18
+ isSelected?: boolean;
19
+ /** Whether the element should be selected by default (uncontrolled). */
20
+ defaultSelected?: boolean;
21
+ /** Handler that is called when the element's selection state changes. */
22
+ onChange?: (isSelected: boolean) => void;
23
+ /** Whether the element is read only. */
24
+ isReadOnly?: boolean;
25
+ }
26
+
27
+ export interface ToggleState {
28
+ /** Whether the toggle is selected. */
29
+ readonly isSelected: Accessor<boolean>;
30
+ /** Whether the toggle is selected by default. */
31
+ readonly defaultSelected: boolean;
32
+ /** Updates selection state. */
33
+ setSelected(isSelected: boolean): void;
34
+ /** Toggle the selection state. */
35
+ toggle(): void;
36
+ }
37
+
38
+ // ============================================
39
+ // IMPLEMENTATION
40
+ // ============================================
41
+
42
+ /**
43
+ * Provides state management for toggle components like checkboxes and switches.
44
+ */
45
+ export function createToggleState(props: MaybeAccessor<ToggleStateOptions> = {}): ToggleState {
46
+ const getProps = () => access(props);
47
+
48
+ // Get initial values
49
+ const initialProps = getProps();
50
+ const initialSelected = initialProps.isSelected ?? initialProps.defaultSelected ?? false;
51
+
52
+ // Create internal signal for uncontrolled mode
53
+ const [internalSelected, setInternalSelected] = createSignal(initialSelected);
54
+
55
+ // Determine if controlled
56
+ const isControlled = () => getProps().isSelected !== undefined;
57
+
58
+ // Get current selection state
59
+ const isSelected: Accessor<boolean> = () => {
60
+ const p = getProps();
61
+ return isControlled() ? (p.isSelected ?? false) : internalSelected();
62
+ };
63
+
64
+ // Update selection state
65
+ function setSelected(value: boolean): void {
66
+ const p = getProps();
67
+ if (p.isReadOnly) {
68
+ return;
69
+ }
70
+
71
+ if (!isControlled()) {
72
+ setInternalSelected(value);
73
+ }
74
+
75
+ p.onChange?.(value);
76
+ }
77
+
78
+ // Toggle selection state
79
+ function toggle(): void {
80
+ const p = getProps();
81
+ if (p.isReadOnly) {
82
+ return;
83
+ }
84
+
85
+ setSelected(!isSelected());
86
+ }
87
+
88
+ return {
89
+ isSelected,
90
+ defaultSelected: initialProps.defaultSelected ?? initialSelected,
91
+ setSelected,
92
+ toggle,
93
+ };
94
+ }
@@ -0,0 +1,5 @@
1
+ export {
2
+ createToggleState,
3
+ type ToggleStateOptions,
4
+ type ToggleState,
5
+ } from './createToggleState';
@@ -3,12 +3,15 @@
3
3
  *
4
4
  * Provides type-safe utilities for working with SolidJS reactivity patterns.
5
5
  */
6
+
6
7
  import { Accessor } from 'solid-js';
8
+
7
9
  /**
8
10
  * A value that may be either a raw value or an accessor function.
9
11
  * This is a common pattern in SolidJS for props that may be reactive.
10
12
  */
11
13
  export type MaybeAccessor<T> = T | Accessor<T>;
14
+
12
15
  /**
13
16
  * Unwraps a MaybeAccessor to get the underlying value.
14
17
  * If the input is a function, it calls it to get the value.
@@ -16,12 +19,18 @@ export type MaybeAccessor<T> = T | Accessor<T>;
16
19
  *
17
20
  * @param value - The value or accessor to unwrap.
18
21
  */
19
- export declare function access<T>(value: MaybeAccessor<T>): T;
22
+ export function access<T>(value: MaybeAccessor<T>): T {
23
+ return typeof value === 'function' ? (value as Accessor<T>)() : value;
24
+ }
25
+
20
26
  /**
21
27
  * A value that may be undefined or an accessor that returns the value or undefined.
22
28
  */
23
29
  export type MaybeAccessorValue<T> = T | undefined | Accessor<T | undefined>;
30
+
24
31
  /**
25
32
  * Checks if a value is an accessor function.
26
33
  */
27
- export declare function isAccessor<T>(value: MaybeAccessor<T>): value is Accessor<T>;
34
+ export function isAccessor<T>(value: MaybeAccessor<T>): value is Accessor<T> {
35
+ return typeof value === 'function';
36
+ }