@simplysm/solid 13.0.98 → 13.0.99

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/docs/helpers.md CHANGED
@@ -1,41 +1,67 @@
1
1
  # Helpers
2
2
 
3
- Source: `src/helpers/*.ts`
3
+ Source: `src/helpers/**`
4
4
 
5
- ## mergeStyles
5
+ ## `mergeStyles`
6
6
 
7
- Utility function that merges CSS styles from multiple sources (objects and strings).
7
+ Utility function that merges CSS styles. Supports string, object, and mixed formats. Converts kebab-case CSS strings to camelCase object properties. Later values take precedence.
8
8
 
9
- ```ts
10
- function mergeStyles(
9
+ ```typescript
10
+ export function mergeStyles(
11
11
  ...styles: (JSX.CSSProperties | string | undefined)[]
12
12
  ): JSX.CSSProperties;
13
13
  ```
14
14
 
15
- - Object styles are merged with later values taking precedence.
16
- - String styles are parsed (semicolon-delimited, kebab-case converted to camelCase).
17
- - `undefined` values are ignored.
15
+ ---
18
16
 
19
- ## createAppStructure
17
+ ## `createAppStructure`
20
18
 
21
- Builds app menus, routes, permissions, and flat menu lists from a declarative structure definition. Supports module-based filtering and permission inference.
19
+ Factory function for defining app navigation structure with type-safe permission inference. Generates routes, menus, and permission trees from a declarative item definition.
22
20
 
23
- ```ts
24
- function createAppStructure<TModule, const TItems extends AppStructureItem<TModule>[]>(
25
- items: TItems,
26
- options: {
27
- basePath: string;
28
- enabledModules?: TModule[];
29
- enabledPerms?: string[];
30
- homeCode?: string;
21
+ ```typescript
22
+ export function createAppStructure<TModule, const TItems extends AppStructureItem<TModule>[]>(
23
+ getOpts: () => {
24
+ items: TItems;
25
+ usableModules?: Accessor<TModule[] | undefined>;
26
+ permRecord?: Accessor<Record<string, boolean> | undefined>;
31
27
  },
32
- ): AppStructure<TModule>;
28
+ ): {
29
+ AppStructureProvider: ParentComponent;
30
+ useAppStructure: () => AppStructure<TModule> & { perms: InferPerms<TItems> };
31
+ };
33
32
  ```
34
33
 
34
+ ### `AppStructure`
35
+
36
+ ```typescript
37
+ export interface AppStructure<TModule> {
38
+ items: AppStructureItem<TModule>[];
39
+ usableRoutes: Accessor<AppRoute[]>;
40
+ usableMenus: Accessor<AppMenu[]>;
41
+ usableFlatMenus: Accessor<AppFlatMenu[]>;
42
+ usablePerms: Accessor<AppPerm<TModule>[]>;
43
+ allFlatPerms: AppFlatPerm<TModule>[];
44
+ getTitleChainByHref(href: string): string[];
45
+ }
46
+ ```
47
+
48
+ | Field | Type | Description |
49
+ |-------|------|-------------|
50
+ | `usableRoutes` | `Accessor<AppRoute[]>` | Routes filtered by module and permission |
51
+ | `usableMenus` | `Accessor<AppMenu[]>` | Menu tree filtered by module and permission |
52
+ | `usableFlatMenus` | `Accessor<AppFlatMenu[]>` | Flat menu list with title chains |
53
+ | `usablePerms` | `Accessor<AppPerm[]>` | Permission tree filtered by module |
54
+ | `allFlatPerms` | `AppFlatPerm[]` | All permissions flattened (static) |
55
+ | `getTitleChainByHref` | `(href) => string[]` | Get breadcrumb title chain for URL |
56
+
35
57
  ### Input Types
36
58
 
37
- ```ts
38
- interface AppStructureGroupItem<TModule> {
59
+ ```typescript
60
+ export type AppStructureItem<TModule> =
61
+ | AppStructureGroupItem<TModule>
62
+ | AppStructureLeafItem<TModule>;
63
+
64
+ export interface AppStructureGroupItem<TModule> {
39
65
  code: string;
40
66
  title: string;
41
67
  icon?: Component<IconProps>;
@@ -44,7 +70,7 @@ interface AppStructureGroupItem<TModule> {
44
70
  children: AppStructureItem<TModule>[];
45
71
  }
46
72
 
47
- interface AppStructureLeafItem<TModule> {
73
+ export interface AppStructureLeafItem<TModule> {
48
74
  code: string;
49
75
  title: string;
50
76
  icon?: Component<IconProps>;
@@ -56,11 +82,7 @@ interface AppStructureLeafItem<TModule> {
56
82
  isNotMenu?: boolean;
57
83
  }
58
84
 
59
- type AppStructureItem<TModule> =
60
- | AppStructureGroupItem<TModule>
61
- | AppStructureLeafItem<TModule>;
62
-
63
- interface AppStructureSubPerm<TModule> {
85
+ export interface AppStructureSubPerm<TModule> {
64
86
  code: string;
65
87
  title: string;
66
88
  modules?: TModule[];
@@ -69,27 +91,37 @@ interface AppStructureSubPerm<TModule> {
69
91
  }
70
92
  ```
71
93
 
72
- ### Output Types
94
+ | Field | Type | Description |
95
+ |-------|------|-------------|
96
+ | `code` | `string` | Unique item identifier |
97
+ | `title` | `string` | Display title |
98
+ | `icon` | `Component<IconProps>` | Navigation icon |
99
+ | `modules` | `TModule[]` | Required modules (any match) |
100
+ | `requiredModules` | `TModule[]` | Strictly required modules (all match) |
101
+ | `children` | `AppStructureItem[]` | Child items (group only) |
102
+ | `component` | `Component` | Page component (leaf only) |
103
+ | `perms` | `("use" \| "edit")[]` | Permission types (leaf only) |
104
+ | `subPerms` | `AppStructureSubPerm[]` | Sub-permission definitions (leaf only) |
105
+ | `isNotMenu` | `boolean` | Exclude from menu (leaf only) |
106
+
107
+ Discriminated union: items with `children` are groups; items without are leaves.
73
108
 
74
- ```ts
75
- interface AppStructure<TModule> {
76
- items: AppStructureItem<TModule>[];
77
- usableRoutes: Accessor<AppRoute[]>;
78
- usableMenus: Accessor<AppMenu[]>;
79
- usableFlatMenus: Accessor<AppFlatMenu[]>;
80
- usablePerms: Accessor<AppPerm<TModule>[]>;
81
- allFlatPerms: AppFlatPerm<TModule>[];
82
- getTitleChainByHref(href: string): string[];
83
- }
109
+ ### Output Types
84
110
 
85
- interface AppMenu {
111
+ ```typescript
112
+ export interface AppMenu {
86
113
  title: string;
87
114
  href?: string;
88
115
  icon?: Component<IconProps>;
89
116
  children?: AppMenu[];
90
117
  }
91
118
 
92
- interface AppPerm<TModule = string> {
119
+ export interface AppRoute {
120
+ path: string;
121
+ component: Component;
122
+ }
123
+
124
+ export interface AppPerm<TModule = string> {
93
125
  title: string;
94
126
  href?: string;
95
127
  modules?: TModule[];
@@ -97,72 +129,78 @@ interface AppPerm<TModule = string> {
97
129
  children?: AppPerm<TModule>[];
98
130
  }
99
131
 
100
- interface AppRoute {
101
- path: string;
102
- component: Component;
103
- }
104
-
105
- interface AppFlatMenu {
106
- titleChain: string[];
107
- href: string;
108
- }
109
-
110
- interface AppFlatPerm<TModule = string> {
132
+ export interface AppFlatPerm<TModule = string> {
111
133
  titleChain: string[];
112
134
  code: string;
113
135
  modulesChain: TModule[][];
114
136
  requiredModulesChain: TModule[][];
115
137
  }
138
+
139
+ export interface AppFlatMenu {
140
+ titleChain: string[];
141
+ href: string;
142
+ }
116
143
  ```
117
144
 
118
- ## createSlot
145
+ ---
119
146
 
120
- Single-item slot pattern for parent-child communication. Used for patterns like `Dialog.Header`, `Select.Header`.
147
+ ## `createSlot`
121
148
 
122
- ```ts
123
- function createSlot<TItem>(): [
149
+ Creates a single-occupancy slot pattern for compound components.
150
+
151
+ ```typescript
152
+ export function createSlot<TItem>(): [
124
153
  SlotComponent: (props: TItem) => null,
125
154
  createSlotAccessor: () => [Accessor<TItem | undefined>, ParentComponent],
126
155
  ];
127
156
  ```
128
157
 
129
- Usage pattern:
158
+ Returns a tuple of `[SlotComponent, createSlotAccessor]`:
159
+ - **`SlotComponent`** -- Rendered inside provider to register slot content (throws if slot already occupied)
160
+ - **`createSlotAccessor`** -- Returns `[accessor, Provider]` for reading and providing the slot
130
161
 
131
- ```tsx
132
- // 1. Create slot at module level
133
- const [HeaderSlot, createHeaderAccessor] = createSlot<{ children: JSX.Element }>();
162
+ ---
134
163
 
135
- // 2. In parent component
136
- const [header, HeaderProvider] = createHeaderAccessor();
164
+ ## `createSlots`
137
165
 
138
- return (
139
- <HeaderProvider>
140
- {props.children}
141
- <Show when={header()}>{header()!.children}</Show>
142
- </HeaderProvider>
143
- );
166
+ Creates a multi-occupancy slot pattern for compound components (multiple items).
144
167
 
145
- // 3. In child usage
146
- <Parent>
147
- <HeaderSlot>My Header Content</HeaderSlot>
148
- {/* other content */}
149
- </Parent>
168
+ ```typescript
169
+ export function createSlots<TItem>(): [
170
+ SlotComponent: (props: TItem) => null,
171
+ createSlotsAccessor: () => [Accessor<TItem[]>, ParentComponent],
172
+ ];
150
173
  ```
151
174
 
152
- ## createSlots
175
+ ### `SlotRegistrar`
153
176
 
154
- Multi-item slot pattern. Like `createSlot` but collects an array of items.
155
-
156
- ```ts
157
- interface SlotRegistrar<TItem> {
177
+ ```typescript
178
+ export interface SlotRegistrar<TItem> {
158
179
  add: (item: TItem) => void;
159
180
  remove: (item: TItem) => void;
160
181
  }
182
+ ```
161
183
 
162
- function createSlots<TItem>(): [
163
- SlotComponent: (props: TItem) => null,
164
- createSlotsAccessor: () => [Accessor<TItem[]>, ParentComponent],
165
- ];
184
+ ---
185
+
186
+ ## `startPointerDrag`
187
+
188
+ Sets up pointer capture and manages pointermove/pointerup lifecycle for drag operations.
189
+
190
+ ```typescript
191
+ export function startPointerDrag(
192
+ target: HTMLElement,
193
+ pointerId: number,
194
+ options: {
195
+ onMove: (e: PointerEvent) => void;
196
+ onEnd: (e: PointerEvent) => void;
197
+ },
198
+ ): void;
166
199
  ```
167
200
 
168
- Items are collected in order of registration and removed on cleanup.
201
+ | Parameter | Type | Description |
202
+ |-----------|------|-------------|
203
+ | `target` | `HTMLElement` | Element to capture pointer on |
204
+ | `pointerId` | `number` | Pointer ID from the initiating PointerEvent |
205
+ | `options.onMove` | `(e: PointerEvent) => void` | Called on each pointermove |
206
+ | `options.onEnd` | `(e: PointerEvent) => void` | Called on pointerup or pointercancel |
package/docs/hooks.md CHANGED
@@ -1,95 +1,99 @@
1
1
  # Hooks
2
2
 
3
- Source: `src/hooks/*.ts`
3
+ Source: `src/hooks/**`
4
4
 
5
- ## useLocalStorage
5
+ ## `useLocalStorage`
6
6
 
7
- localStorage-backed reactive signal. Keys are prefixed with `ConfigContext.clientName`.
7
+ LocalStorage-based storage hook. Always uses localStorage regardless of SyncStorage settings. Keys are prefixed with `clientName`.
8
8
 
9
- ```ts
10
- function useLocalStorage<TValue>(
9
+ ```typescript
10
+ export function useLocalStorage<TValue>(
11
11
  key: string,
12
12
  initialValue?: TValue,
13
13
  ): [Accessor<TValue | undefined>, StorageSetter<TValue>];
14
-
15
- type StorageSetter<TValue> = (
16
- value: TValue | undefined | ((prev: TValue | undefined) => TValue | undefined),
17
- ) => TValue | undefined;
18
14
  ```
19
15
 
20
- - Always uses localStorage regardless of `SyncStorageProvider`.
21
- - Used for device-specific data (auth tokens, local state).
22
- - Setting `undefined` removes the item from localStorage.
16
+ | Parameter | Type | Description |
17
+ |-----------|------|-------------|
18
+ | `key` | `string` | Storage key (auto-prefixed with `clientName`) |
19
+ | `initialValue` | `TValue` | Default value if nothing stored |
20
+
21
+ ---
23
22
 
24
- ## useSyncConfig
23
+ ## `useSyncConfig`
25
24
 
26
- Storage-synced configuration signal. Uses `SyncStorageProvider` adapter if available, falls back to localStorage.
25
+ Reactive signal that syncs to storage via SyncStorageProvider (falls back to localStorage). Designed for data that should persist and sync across devices.
27
26
 
28
- ```ts
29
- function useSyncConfig<TValue>(
27
+ ```typescript
28
+ export function useSyncConfig<TValue>(
30
29
  key: string,
31
30
  defaultValue: TValue,
32
31
  ): [Accessor<TValue>, Setter<TValue>, Accessor<boolean>];
33
32
  ```
34
33
 
35
- - Returns `[value, setValue, ready]`.
36
- - `ready()` becomes `true` after the initial value is loaded from storage.
37
- - When the adapter changes via `useSyncStorage().configure()`, re-reads from the new adapter.
38
- - Used for data that should persist and sync across devices (theme, preferences, DataSheet configs).
34
+ | Parameter | Type | Description |
35
+ |-----------|------|-------------|
36
+ | `key` | `string` | Storage key (auto-prefixed with `clientName`) |
37
+ | `defaultValue` | `TValue` | Default value |
38
+
39
+ Returns `[value, setValue, ready]` where `ready()` is `true` after initial storage read completes.
40
+
41
+ ---
39
42
 
40
- ## useLogger
43
+ ## `useLogger`
41
44
 
42
- Logging hook with pluggable adapter. Falls back to `consola` if `LoggerProvider` is not present.
45
+ Logging hook that delegates to LoggerProvider adapter (defaults to consola).
43
46
 
44
- ```ts
45
- interface Logger {
47
+ ```typescript
48
+ export function useLogger(): Logger;
49
+
50
+ export interface Logger {
46
51
  log: (...args: unknown[]) => void;
47
52
  info: (...args: unknown[]) => void;
48
53
  warn: (...args: unknown[]) => void;
49
54
  error: (...args: unknown[]) => void;
50
55
  configure: (fn: (origin: LogAdapter) => LogAdapter) => void;
51
56
  }
52
-
53
- function useLogger(): Logger;
54
57
  ```
55
58
 
56
- `configure` is only usable inside `LoggerProvider`.
59
+ ---
57
60
 
58
- ## createControllableSignal
61
+ ## `createControllableSignal`
59
62
 
60
- Signal hook supporting the controlled/uncontrolled pattern. Used extensively by form components.
63
+ Signal hook supporting the controlled/uncontrolled pattern.
61
64
 
62
- ```ts
63
- function createControllableSignal<TValue>(options: {
65
+ ```typescript
66
+ export function createControllableSignal<TValue>(options: {
64
67
  value: Accessor<TValue>;
65
68
  onChange: Accessor<((value: TValue) => void) | undefined>;
66
69
  }): [Accessor<TValue>, (newValue: TValue | ((prev: TValue) => TValue)) => TValue];
67
70
  ```
68
71
 
69
- - When `onChange` is provided: controlled mode, value managed externally.
70
- - When `onChange` returns `undefined`: uncontrolled mode, uses internal state.
71
- - Supports functional setter: `setValue(prev => !prev)`.
72
+ - When `onChange` is provided: controlled mode (value managed externally)
73
+ - When `onChange` is absent: uncontrolled mode (uses internal state)
74
+ - Supports functional setter: `setValue(prev => !prev)`
75
+
76
+ ---
72
77
 
73
- ## createControllableStore
78
+ ## `createControllableStore`
74
79
 
75
- Store hook supporting the controlled/uncontrolled pattern. Uses `solid-js/store` for fine-grained reactivity.
80
+ Store hook supporting the controlled/uncontrolled pattern. Supports all `SetStoreFunction` overloads (path-based, produce, reconcile).
76
81
 
77
- ```ts
78
- function createControllableStore<TValue extends object>(options: {
82
+ ```typescript
83
+ export function createControllableStore<TValue extends object>(options: {
79
84
  value: () => TValue;
80
85
  onChange: () => ((value: TValue) => void) | undefined;
81
86
  }): [TValue, SetStoreFunction<TValue>];
82
87
  ```
83
88
 
84
- - Supports all `SetStoreFunction` overloads (path-based, produce, reconcile).
85
- - In controlled mode: calls `onChange` with a deep clone when the store changes.
89
+ ---
86
90
 
87
- ## createIMEHandler
91
+ ## `createIMEHandler`
88
92
 
89
- IME composition handling hook. Delays value commits during IME composition (e.g., Korean input) to prevent DOM recreation and composition breakage.
93
+ IME composition handling hook. Delays value changes during IME composition (e.g., Korean) to prevent DOM recreation.
90
94
 
91
- ```ts
92
- function createIMEHandler(setValue: (value: string) => void): {
95
+ ```typescript
96
+ export function createIMEHandler(setValue: (value: string) => void): {
93
97
  composingValue: Accessor<string | null>;
94
98
  handleCompositionStart: () => void;
95
99
  handleInput: (value: string, isComposing: boolean) => void;
@@ -98,46 +102,41 @@ function createIMEHandler(setValue: (value: string) => void): {
98
102
  };
99
103
  ```
100
104
 
101
- - During composition: only `composingValue` is updated (for display).
102
- - On `compositionEnd`: delays `setValue` via `setTimeout(0)`.
103
- - `flushComposition()`: immediately commits any pending value.
105
+ ---
104
106
 
105
- ## createMountTransition
107
+ ## `createMountTransition`
106
108
 
107
- Mount/unmount animation state hook.
109
+ Mount transition hook for open/close CSS animations. Returns `mounted` for DOM rendering and `animating` for CSS class toggling.
108
110
 
109
- ```ts
110
- function createMountTransition(open: () => boolean): {
111
+ ```typescript
112
+ export function createMountTransition(open: () => boolean): {
111
113
  mounted: () => boolean;
112
114
  animating: () => boolean;
113
115
  unmount: () => void;
114
116
  };
115
117
  ```
116
118
 
117
- - `open=true`: immediately sets `mounted=true`, then `animating=true` after double `requestAnimationFrame`.
118
- - `open=false`: immediately sets `animating=false`, then `mounted=false` after `transitionend` or 200ms fallback.
119
- - Use `mounted()` for DOM rendering, `animating()` for CSS class toggling.
120
- - Call `unmount()` to manually remove from DOM (e.g., in `onTransitionEnd`).
119
+ - `open=true`: `mounted=true` immediately, `animating=true` after double rAF
120
+ - `open=false`: `animating=false` immediately, `mounted=false` after transitionend or 200ms fallback
121
121
 
122
- ## useRouterLink
122
+ ---
123
123
 
124
- Router navigation hook supporting modifier keys (Ctrl+click, Shift+click).
124
+ ## `useRouterLink`
125
125
 
126
- ```ts
127
- interface RouterLinkOptions {
128
- href: string;
129
- state?: Record<string, unknown>;
130
- window?: {
131
- width?: number; // default: 800
132
- height?: number; // default: 800
133
- };
134
- }
126
+ Router navigation hook with modifier key support.
135
127
 
136
- function useRouterLink(): (
128
+ ```typescript
129
+ export function useRouterLink(): (
137
130
  options: RouterLinkOptions,
138
131
  ) => (e: MouseEvent | KeyboardEvent) => void;
132
+
133
+ export interface RouterLinkOptions {
134
+ href: string;
135
+ state?: Record<string, unknown>;
136
+ window?: { width?: number; height?: number };
137
+ }
139
138
  ```
140
139
 
141
- - Normal click: SPA routing via `useNavigate`.
142
- - Ctrl/Alt + click: opens in new tab.
143
- - Shift + click: opens in new window with specified dimensions.
140
+ - Normal click: SPA routing via `useNavigate`
141
+ - Ctrl/Alt + click: new tab
142
+ - Shift + click: new window with configurable size