@luna_ui/luna 0.3.5 → 0.5.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.
- package/dist/cli.mjs +1 -1
- package/dist/{index-CyEkcO3_.d.ts → index-vO066aMd.d.ts} +17 -6
- package/dist/index.d.ts +1 -1
- package/dist/index.js +1 -1
- package/dist/jsx-dev-runtime.js +1 -1
- package/dist/jsx-runtime.d.ts +1 -1
- package/dist/jsx-runtime.js +1 -1
- package/dist/src-DviLMStS.js +1 -0
- package/package.json +1 -1
- package/src/hydration/createHydrator.ts +62 -0
- package/src/hydration/delegate.ts +62 -0
- package/src/hydration/drag.ts +214 -0
- package/src/hydration/index.ts +12 -0
- package/src/hydration/keyboard.ts +64 -0
- package/src/hydration/toggle.ts +101 -0
- package/src/index.ts +26 -8
- package/tests/__screenshots__/{preact-signals-comparison.test.ts/DOM-Rendering-Comparison---Reactive-Updates-text-updates-match-1.png → apg.test.ts/APG-Components---Accessibility-Tests-Button-Pattern-disabled-button-has-aria-disabled-1.png} +0 -0
- package/tests/apg.test.ts +466 -0
- package/tests/debounced.test.ts +165 -0
- package/tests/dom.test.ts +3 -2
- package/tests/issue-11-show-null-to-truthy.test.ts +176 -0
- package/tests/solidjs-api.test.ts +5 -4
- package/dist/src-CHiGeWfy.js +0 -1
- package/tests/__screenshots__/context.test.ts/Context-API-context-with-reactive-effects-context-value-accessible-in-effect-1.png +0 -0
- package/tests/__screenshots__/dom.test.ts/DOM-API-For-component--SolidJS-style--For-updates-when-signal-changes-1.png +0 -0
- package/tests/__screenshots__/dom.test.ts/DOM-API-Show-component--SolidJS-style--Show-accepts-children-as-function-1.png +0 -0
- package/tests/__screenshots__/dom.test.ts/DOM-API-Show-component--SolidJS-style--Show-toggles-visibility-1.png +0 -0
- package/tests/__screenshots__/dom.test.ts/DOM-API-createElement-createElement-with-dynamic-attribute-1.png +0 -0
- package/tests/__screenshots__/dom.test.ts/DOM-API-createElement-createElement-with-dynamic-style-1.png +0 -0
- package/tests/__screenshots__/dom.test.ts/DOM-API-createElementNs--SVG-support--createElementNs-with-dynamic-attribute-1.png +0 -0
- package/tests/__screenshots__/dom.test.ts/DOM-API-effect-with-DOM-effect-tracks-signal-changes-1.png +0 -0
- package/tests/__screenshots__/dom.test.ts/DOM-API-forEach--list-rendering--forEach-handles-clear-to-empty-1.png +0 -0
- package/tests/__screenshots__/dom.test.ts/DOM-API-forEach--list-rendering--forEach-handles-empty-array-1.png +0 -0
- package/tests/__screenshots__/dom.test.ts/DOM-API-forEach--list-rendering--forEach-removes-items-1.png +0 -0
- package/tests/__screenshots__/dom.test.ts/DOM-API-forEach--list-rendering--forEach-renders-initial-list-1.png +0 -0
- package/tests/__screenshots__/dom.test.ts/DOM-API-forEach--list-rendering--forEach-updates-when-items-change-1.png +0 -0
- package/tests/__screenshots__/dom.test.ts/DOM-API-forEach-with-SVG-elements-forEach-handles-empty-to-non-empty-transition-in-SVG-1.png +0 -0
- package/tests/__screenshots__/dom.test.ts/DOM-API-forEach-with-SVG-elements-forEach-handles-reordering-in-SVG-1.png +0 -0
- package/tests/__screenshots__/dom.test.ts/DOM-API-forEach-with-SVG-elements-forEach-updates-SVG-elements-when-signal-changes-1.png +0 -0
- package/tests/__screenshots__/dom.test.ts/DOM-API-forEach-with-SVG-elements-forEach-with-nested-SVG-groups-1.png +0 -0
- package/tests/__screenshots__/dom.test.ts/DOM-API-ref-callback--JSX-style--ref-callback-with-nested-elements-1.png +0 -0
- package/tests/__screenshots__/dom.test.ts/DOM-API-show--conditional-rendering--show-creates-a-node-1.png +0 -0
- package/tests/__screenshots__/dom.test.ts/DOM-API-show--conditional-rendering--show-with-false-condition-creates-placeholder-1.png +0 -0
- package/tests/__screenshots__/dom.test.ts/DOM-API-text-nodes-textDyn-creates-reactive-text-node-1.png +0 -0
- package/tests/__screenshots__/integration.test.ts/Integration--Nested-Components-with-Context-Complex-nested-scenario-forEach-renders-correctly-without-show--initial-items--1.png +0 -0
- package/tests/__screenshots__/integration.test.ts/Integration--Nested-Components-with-Context-Complex-nested-scenario-forEach-with-context-renders-correctly-without-show-1.png +0 -0
- package/tests/__screenshots__/integration.test.ts/Integration--Nested-Components-with-Context-Complex-nested-scenario-nested-components-with-context--forEach--and-show-1.png +0 -0
- package/tests/__screenshots__/integration.test.ts/Integration--Nested-Components-with-Context-Complex-nested-scenario-show-and-forEach-inherit-context-from-Owner--fixed--1.png +0 -0
- package/tests/__screenshots__/integration.test.ts/Integration--Nested-Components-with-Context-Complex-nested-scenario-show-and-forEach-work-together--context-uses-default--1.png +0 -0
- package/tests/__screenshots__/integration.test.ts/Integration--Nested-Components-with-Context-Context---ForEach-integration-forEach-items-can-access-context-1.png +0 -0
- package/tests/__screenshots__/integration.test.ts/Integration--Nested-Components-with-Context-ForEach-with-reactive-updates-forEach-renders-initial-list-1.png +0 -0
- package/tests/__screenshots__/integration.test.ts/Integration--Nested-Components-with-Context-ForEach-with-reactive-updates-forEach-updates-when-signal-changes-1.png +0 -0
- package/tests/__screenshots__/integration.test.ts/Integration--Nested-Components-with-Context-ForEach-with-reactive-updates-forEach-with-object-items-1.png +0 -0
- package/tests/__screenshots__/integration.test.ts/Integration--Nested-Components-with-Context-Show--conditional-rendering--show-hides-when-condition-is-false-1.png +0 -0
- package/tests/__screenshots__/integration.test.ts/Integration--Nested-Components-with-Context-Show--conditional-rendering--show-renders-when-condition-is-true-1.png +0 -0
- package/tests/__screenshots__/integration.test.ts/Integration--Nested-Components-with-Context-Show--conditional-rendering--show-toggles-from-false-to-true-1.png +0 -0
- package/tests/__screenshots__/integration.test.ts/Integration--Nested-Components-with-Context-Show--conditional-rendering--show-toggles-reactively-1.png +0 -0
- package/tests/__screenshots__/lifecycle.test.ts/onCleanup-in-Component-Body--Solid-js-style--event-listener-pattern--Solid-js-docs-example--1.png +0 -0
- package/tests/__screenshots__/lifecycle.test.ts/onCleanup-in-Component-Body--Solid-js-style--multiple-cleanups-in-component-body--LIFO-order--1.png +0 -0
- package/tests/__screenshots__/lifecycle.test.ts/onCleanup-in-Component-Body--Solid-js-style--onCleanup-in-component-body-runs-on-unmount-1.png +0 -0
- package/tests/__screenshots__/lifecycle.test.ts/onCleanup-in-Component-Body--Solid-js-style--onCleanup-works-with-For-loop-items--component-body-style--1.png +0 -0
- package/tests/__screenshots__/lifecycle.test.ts/onCleanup-in-Component-Body--Solid-js-style--timer-cleanup-pattern--Solid-js-style--1.png +0 -0
- package/tests/__screenshots__/lifecycle.test.ts/onCleanup-in-Effects-effect-cleanup-runs-before-re-run-1.png +0 -0
- package/tests/__screenshots__/preact-signals-comparison.test.ts/Bulk-Updates-large-list-update-1.png +0 -0
- package/tests/__screenshots__/preact-signals-comparison.test.ts/Bulk-Updates-nested-batch-operations-1.png +0 -0
- package/tests/__screenshots__/preact-signals-comparison.test.ts/Bulk-Updates-rapid-sequential-updates-1.png +0 -0
- package/tests/__screenshots__/preact-signals-comparison.test.ts/DOM-Rendering-Comparison---Conditional-Show-component---visible-1.png +0 -0
- package/tests/__screenshots__/preact-signals-comparison.test.ts/DOM-Rendering-Comparison---Conditional-show-hide-element---visible-1.png +0 -0
- package/tests/__screenshots__/preact-signals-comparison.test.ts/DOM-Rendering-Comparison---Fragments-fragment-with-list-1.png +0 -0
- package/tests/__screenshots__/preact-signals-comparison.test.ts/DOM-Rendering-Comparison---Fragments-nested-fragments-1.png +0 -0
- package/tests/__screenshots__/preact-signals-comparison.test.ts/DOM-Rendering-Comparison---Fragments-simple-fragment-1.png +0 -0
- package/tests/__screenshots__/preact-signals-comparison.test.ts/DOM-Rendering-Comparison---Reactive-Updates-conditional-toggle-updates-1.png +0 -0
- package/tests/__screenshots__/preact-signals-comparison.test.ts/DOM-Rendering-Comparison---Reactive-Updates-list-addition-updates-match-1.png +0 -0
- package/tests/__screenshots__/preact-signals-comparison.test.ts/DOM-Rendering-Comparison---Reactive-Updates-list-removal-updates-match-1.png +0 -0
- package/tests/__screenshots__/preact-signals-comparison.test.ts/Dynamic-Attributes-Comparison-dynamic-className-updates-1.png +0 -0
- package/tests/__screenshots__/preact-signals-comparison.test.ts/Dynamic-Attributes-Comparison-dynamic-style-updates-1.png +0 -0
- package/tests/__screenshots__/preact-signals-comparison.test.ts/Dynamic-Attributes-Comparison-multiple-dynamic-attributes-1.png +0 -0
- package/tests/__screenshots__/preact-signals-comparison.test.ts/Edge-Cases-deeply-nested-conditionals-1.png +0 -0
- package/tests/__screenshots__/preact-signals-comparison.test.ts/Edge-Cases-list-transitions-from-empty-to-populated-1.png +0 -0
- package/tests/__screenshots__/preact-signals-comparison.test.ts/Edge-Cases-list-transitions-from-populated-to-empty-1.png +0 -0
- package/tests/__screenshots__/preact-signals-comparison.test.ts/Effect-Cleanup-Comparison-nested-effects-cleanup-order-1.png +0 -0
- package/tests/__screenshots__/preact-signals-comparison.test.ts/Effect-Cleanup-Comparison-nested-effects-with-inner-signal-change-1.png +0 -0
- package/tests/__screenshots__/preact-signals-comparison.test.ts/Effect-Cleanup-Comparison-onCleanup-is-called-when-effect-re-runs-1.png +0 -0
- package/tests/__screenshots__/preact-signals-comparison.test.ts/Effect-Cleanup-Comparison-onCleanup-with-resource-simulation-1.png +0 -0
- package/tests/__screenshots__/preact-signals-comparison.test.ts/Fragment-Comparison-with-Preact-Fragment-with-multiple-children--no-wrapper--1.png +0 -0
- package/tests/__screenshots__/preact-signals-comparison.test.ts/Fragment-Comparison-with-Preact-Fragment-with-no-children-1.png +0 -0
- package/tests/__screenshots__/preact-signals-comparison.test.ts/Fragment-Comparison-with-Preact-fragment-with-list-1.png +0 -0
- package/tests/__screenshots__/preact-signals-comparison.test.ts/Fragment-Comparison-with-Preact-nested-Fragments-work-correctly-1.png +0 -0
- package/tests/__screenshots__/preact-signals-comparison.test.ts/List-Reordering-complex-reordering-with-additions-and-removals-1.png +0 -0
- package/tests/__screenshots__/preact-signals-comparison.test.ts/List-Reordering-insert-in-middle-1.png +0 -0
- package/tests/__screenshots__/preact-signals-comparison.test.ts/List-Reordering-remove-from-middle-1.png +0 -0
- package/tests/__screenshots__/preact-signals-comparison.test.ts/List-Reordering-reverse-list-order-1.png +0 -0
- package/tests/__screenshots__/preact-signals-comparison.test.ts/List-Reordering-shuffle-list-1.png +0 -0
- package/tests/__screenshots__/preact-signals-comparison.test.ts/Luna-Conditional-Rendering-Show-component-renders-when-condition-is-true-1.png +0 -0
- package/tests/__screenshots__/preact-signals-comparison.test.ts/Luna-Conditional-Rendering-show-renders-content-when-initially-true-1.png +0 -0
- package/tests/__screenshots__/preact-signals-comparison.test.ts/Luna-Conditional-Rendering-show-toggles-visibility-dynamically-1.png +0 -0
- package/tests/__screenshots__/preact-signals-comparison.test.ts/Memo-Dependency-Chain-conditional-memo-dependencies-1.png +0 -0
- package/tests/__screenshots__/preact-signals-comparison.test.ts/Signal-Behavior-Comparison-basic-signal-get-set-produces-same-values-1.png +0 -0
- package/tests/__screenshots__/preact-signals-comparison.test.ts/Signal-Behavior-Comparison-batch-updates-produce-same-final-values-1.png +0 -0
- package/tests/__screenshots__/preact-signals-comparison.test.ts/Untrack-and-Peek-Behavior-peek-reads-value-without-tracking-1.png +0 -0
- package/tests/__screenshots__/preact-signals-comparison.test.ts/Untrack-and-Peek-Behavior-selective-tracking-with-untrack-1.png +0 -0
- package/tests/__screenshots__/preact-signals-comparison.test.ts/Untrack-and-Peek-Behavior-untrack-prevents-dependency-tracking-1.png +0 -0
- package/tests/__screenshots__/resource.test.ts/Resource-API--SolidJS-style--reactivity-accessor-is-reactive-1.png +0 -0
- package/tests/__screenshots__/resource.test.ts/Resource-API-AsyncState-helpers-stateError-returns-empty-string-for-non-failure-1.png +0 -0
- package/tests/__screenshots__/resource.test.ts/Resource-API-AsyncState-helpers-stateError-returns-undefined-for-non-failure-1.png +0 -0
- package/tests/__screenshots__/resource.test.ts/Resource-API-AsyncState-helpers-stateIsFailure-and-stateError-1.png +0 -0
- package/tests/__screenshots__/resource.test.ts/Resource-API-AsyncState-helpers-stateIsPending-1.png +0 -0
- package/tests/__screenshots__/resource.test.ts/Resource-API-AsyncState-helpers-stateIsSuccess-and-stateValue-1.png +0 -0
- package/tests/__screenshots__/resource.test.ts/Resource-API-AsyncState-helpers-stateValue-returns-undefined-for-non-success-1.png +0 -0
- package/tests/__screenshots__/resource.test.ts/Resource-API-createDeferred-reject-transitions-to-failure-1.png +0 -0
- package/tests/__screenshots__/resource.test.ts/Resource-API-createDeferred-resolve-transitions-to-success-1.png +0 -0
- package/tests/__screenshots__/resource.test.ts/Resource-API-createDeferred-returns-resource--resolve--and-reject-functions-1.png +0 -0
- package/tests/__screenshots__/resource.test.ts/Resource-API-createDeferred-starts-in-pending-state-1.png +0 -0
- package/tests/__screenshots__/resource.test.ts/Resource-API-createResource-async-resolve-works-1.png +0 -0
- package/tests/__screenshots__/resource.test.ts/Resource-API-createResource-starts-in-pending-state-1.png +0 -0
- package/tests/__screenshots__/resource.test.ts/Resource-API-createResource-transitions-to-failure-on-reject-1.png +0 -0
- package/tests/__screenshots__/resource.test.ts/Resource-API-createResource-transitions-to-success-on-resolve-1.png +0 -0
- package/tests/__screenshots__/resource.test.ts/Resource-API-integration-with-Promise-can-wrap-fetch-like-async-operations-1.png +0 -0
- package/tests/__screenshots__/resource.test.ts/Resource-API-integration-with-Promise-works-with-setTimeout-simulation-1.png +0 -0
- package/tests/__screenshots__/resource.test.ts/Resource-API-resourceGet-vs-resourcePeek-resourceGet-tracks-dependencies-1.png +0 -0
- package/tests/__screenshots__/resource.test.ts/Resource-API-resourceGet-vs-resourcePeek-resourcePeek-does-not-track-dependencies-1.png +0 -0
- package/tests/__screenshots__/resource.test.ts/Resource-API-resourceRefetch-refetch-resets-to-pending-and-re-runs-fetcher-1.png +0 -0
- package/tests/__screenshots__/solidjs-api.test.ts/Portal-component-Portal-renders-children-to-body-by-default-1.png +0 -0
- package/tests/__screenshots__/solidjs-api.test.ts/Portal-component-Portal-renders-to-selector-mount-target-1.png +0 -0
- package/tests/__screenshots__/solidjs-api.test.ts/SolidJS-API-compatibility-createEffect-tracks-dependencies-automatically-1.png +0 -0
- package/tests/__screenshots__/solidjs-api.test.ts/Switch-Match-component-Switch-with-accessor-condition-in-Match-1.png +0 -0
- package/tests/__screenshots__/solidjs-api.test.ts/Switch-Match-component-Switch-with-multiple-Match-components-1.png +0 -0
- package/tests/__screenshots__/solidjs-api.test.ts/Switch-Match-component-Switch-with-single-Match-and-fallback-1.png +0 -0
- package/tests/__screenshots__/solidjs-api.test.ts/Switch-Match-components-Switch-updates-DOM-when-signal-changes-1.png +0 -0
- package/tests/__screenshots__/solidjs-api.test.ts/on---utility-on-tracks-multiple-dependencies-1.png +0 -0
- package/tests/__screenshots__/solidjs-api.test.ts/on---utility-on-tracks-single-dependency-1.png +0 -0
- package/tests/__screenshots__/solidjs-api.test.ts/on---utility-on-with-defer-option-skips-initial-run-1.png +0 -0
- package/tests/__screenshots__/store.test.ts/createStore-Arrays-array-updates-work-1.png +0 -0
- package/tests/__screenshots__/store.test.ts/createStore-Reactivity-only-triggers-when-accessed-property-changes-1.png +0 -0
- package/tests/__screenshots__/store.test.ts/createStore-Reactivity-parent-path-change-notifies-child-accessors-1.png +0 -0
- package/tests/__screenshots__/store.test.ts/createStore-Reactivity-tracks-nested-property-access-1.png +0 -0
- package/tests/__screenshots__/store.test.ts/createStore-Reactivity-tracks-property-access-in-effects-1.png +0 -0
|
@@ -0,0 +1,64 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* keyboard - Keyboard event handler helper
|
|
3
|
+
*
|
|
4
|
+
* Map keyboard keys to handler functions.
|
|
5
|
+
*/
|
|
6
|
+
|
|
7
|
+
export type KeyboardHandlers = {
|
|
8
|
+
[key: string]: (event: KeyboardEvent) => void;
|
|
9
|
+
};
|
|
10
|
+
|
|
11
|
+
/**
|
|
12
|
+
* Set up keyboard handlers on an element or document
|
|
13
|
+
*
|
|
14
|
+
* @example
|
|
15
|
+
* ```ts
|
|
16
|
+
* // Handle Escape on document
|
|
17
|
+
* keyboard(document, {
|
|
18
|
+
* Escape: () => close()
|
|
19
|
+
* });
|
|
20
|
+
*
|
|
21
|
+
* // Handle arrow keys on a specific element
|
|
22
|
+
* keyboard(slider, {
|
|
23
|
+
* ArrowUp: () => increment(),
|
|
24
|
+
* ArrowDown: () => decrement(),
|
|
25
|
+
* ArrowLeft: () => decrement(),
|
|
26
|
+
* ArrowRight: () => increment()
|
|
27
|
+
* });
|
|
28
|
+
* ```
|
|
29
|
+
*/
|
|
30
|
+
export function keyboard(
|
|
31
|
+
target: Element | Document | null,
|
|
32
|
+
handlers: KeyboardHandlers
|
|
33
|
+
): () => void {
|
|
34
|
+
if (!target) return () => {};
|
|
35
|
+
|
|
36
|
+
const handler = (e: Event) => {
|
|
37
|
+
const key = (e as KeyboardEvent).key;
|
|
38
|
+
const fn = handlers[key];
|
|
39
|
+
if (fn) {
|
|
40
|
+
fn(e as KeyboardEvent);
|
|
41
|
+
}
|
|
42
|
+
};
|
|
43
|
+
|
|
44
|
+
target.addEventListener('keydown', handler);
|
|
45
|
+
|
|
46
|
+
// Return cleanup function
|
|
47
|
+
return () => {
|
|
48
|
+
target.removeEventListener('keydown', handler);
|
|
49
|
+
};
|
|
50
|
+
}
|
|
51
|
+
|
|
52
|
+
/**
|
|
53
|
+
* Handle Escape key to close something
|
|
54
|
+
*
|
|
55
|
+
* @example
|
|
56
|
+
* ```ts
|
|
57
|
+
* onEscape(() => {
|
|
58
|
+
* dialog.dataset.state = 'closed';
|
|
59
|
+
* });
|
|
60
|
+
* ```
|
|
61
|
+
*/
|
|
62
|
+
export function onEscape(handler: () => void): () => void {
|
|
63
|
+
return keyboard(document, { Escape: handler });
|
|
64
|
+
}
|
|
@@ -0,0 +1,101 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* toggle - Binary state toggle helper
|
|
3
|
+
*
|
|
4
|
+
* Toggles between two states on click, using data-* or aria-* attributes.
|
|
5
|
+
* CSS handles visual changes via attribute selectors.
|
|
6
|
+
*/
|
|
7
|
+
|
|
8
|
+
export interface ToggleOptions {
|
|
9
|
+
/**
|
|
10
|
+
* Selector for the element to toggle state on.
|
|
11
|
+
* If not provided, the trigger element itself is used.
|
|
12
|
+
* Use closest() to find ancestor.
|
|
13
|
+
*/
|
|
14
|
+
target?: string;
|
|
15
|
+
|
|
16
|
+
/**
|
|
17
|
+
* The two states to toggle between.
|
|
18
|
+
* @default ['open', 'closed'] for data-state
|
|
19
|
+
* @default ['true', 'false'] for aria-checked
|
|
20
|
+
*/
|
|
21
|
+
states?: [string, string];
|
|
22
|
+
|
|
23
|
+
/**
|
|
24
|
+
* Attribute to update.
|
|
25
|
+
* @default 'data-state'
|
|
26
|
+
*/
|
|
27
|
+
attribute?: string;
|
|
28
|
+
|
|
29
|
+
/**
|
|
30
|
+
* Callback when state changes.
|
|
31
|
+
*/
|
|
32
|
+
onChange?: (state: string, element: Element) => void;
|
|
33
|
+
}
|
|
34
|
+
|
|
35
|
+
/**
|
|
36
|
+
* Set up click-to-toggle behavior on matching elements
|
|
37
|
+
*
|
|
38
|
+
* @example
|
|
39
|
+
* ```ts
|
|
40
|
+
* // Toggle data-state on parent [data-accordion-item]
|
|
41
|
+
* toggle(el, '[data-accordion-trigger]', {
|
|
42
|
+
* target: '[data-accordion-item]',
|
|
43
|
+
* states: ['open', 'closed']
|
|
44
|
+
* });
|
|
45
|
+
*
|
|
46
|
+
* // Toggle aria-checked on the button itself
|
|
47
|
+
* toggle(el, '[data-switch-toggle]', {
|
|
48
|
+
* attribute: 'aria-checked',
|
|
49
|
+
* states: ['true', 'false']
|
|
50
|
+
* });
|
|
51
|
+
* ```
|
|
52
|
+
*/
|
|
53
|
+
export function toggle(
|
|
54
|
+
root: Element,
|
|
55
|
+
selector: string,
|
|
56
|
+
options: ToggleOptions = {}
|
|
57
|
+
): () => void {
|
|
58
|
+
const {
|
|
59
|
+
target,
|
|
60
|
+
attribute = 'data-state',
|
|
61
|
+
states = attribute === 'aria-checked' ? ['true', 'false'] : ['open', 'closed'],
|
|
62
|
+
onChange,
|
|
63
|
+
} = options;
|
|
64
|
+
|
|
65
|
+
const [stateA, stateB] = states;
|
|
66
|
+
const handlers: Array<{ el: Element; handler: EventListener }> = [];
|
|
67
|
+
|
|
68
|
+
root.querySelectorAll(selector).forEach((trigger) => {
|
|
69
|
+
const handler = () => {
|
|
70
|
+
// Find target element
|
|
71
|
+
const targetEl = target
|
|
72
|
+
? trigger.closest(target)
|
|
73
|
+
: trigger;
|
|
74
|
+
|
|
75
|
+
if (!targetEl) return;
|
|
76
|
+
|
|
77
|
+
// Get current state and toggle
|
|
78
|
+
const current = targetEl.getAttribute(attribute);
|
|
79
|
+
const next = current === stateA ? stateB : stateA;
|
|
80
|
+
|
|
81
|
+
targetEl.setAttribute(attribute, next);
|
|
82
|
+
|
|
83
|
+
// Also update aria-checked if toggling data-state on a button
|
|
84
|
+
if (attribute === 'data-state' && targetEl.tagName === 'BUTTON') {
|
|
85
|
+
targetEl.setAttribute('aria-checked', next === stateA ? 'true' : 'false');
|
|
86
|
+
}
|
|
87
|
+
|
|
88
|
+
onChange?.(next, targetEl);
|
|
89
|
+
};
|
|
90
|
+
|
|
91
|
+
trigger.addEventListener('click', handler);
|
|
92
|
+
handlers.push({ el: trigger, handler });
|
|
93
|
+
});
|
|
94
|
+
|
|
95
|
+
// Return cleanup function
|
|
96
|
+
return () => {
|
|
97
|
+
handlers.forEach(({ el, handler }) => {
|
|
98
|
+
el.removeEventListener('click', handler);
|
|
99
|
+
});
|
|
100
|
+
};
|
|
101
|
+
}
|
package/src/index.ts
CHANGED
|
@@ -23,8 +23,11 @@ export interface ForProps<T> {
|
|
|
23
23
|
export interface ShowProps<T> {
|
|
24
24
|
when: T | Accessor<T>;
|
|
25
25
|
fallback?: LunaNode;
|
|
26
|
-
/**
|
|
27
|
-
|
|
26
|
+
/**
|
|
27
|
+
* Children receives an accessor function (SolidJS-style).
|
|
28
|
+
* Use: {(item) => <p>{item()}</p>}
|
|
29
|
+
*/
|
|
30
|
+
children: (() => LunaNode) | ((item: Accessor<NonNullable<T>>) => LunaNode);
|
|
28
31
|
}
|
|
29
32
|
|
|
30
33
|
export interface IndexProps<T> {
|
|
@@ -48,8 +51,11 @@ export interface ProviderProps<T> {
|
|
|
48
51
|
|
|
49
52
|
export interface MatchProps<T> {
|
|
50
53
|
when: T | Accessor<T>;
|
|
51
|
-
/**
|
|
52
|
-
|
|
54
|
+
/**
|
|
55
|
+
* Children receives an accessor function (SolidJS-style).
|
|
56
|
+
* Use: {(item) => <p>{item()}</p>}
|
|
57
|
+
*/
|
|
58
|
+
children: (() => LunaNode) | ((item: Accessor<NonNullable<T>>) => LunaNode);
|
|
53
59
|
}
|
|
54
60
|
|
|
55
61
|
export interface SwitchProps {
|
|
@@ -149,7 +155,7 @@ import {
|
|
|
149
155
|
portalToSelector,
|
|
150
156
|
portalWithShadow,
|
|
151
157
|
portalToElementWithShadow,
|
|
152
|
-
} from "../../../target/js/release/build/
|
|
158
|
+
} from "../../../target/js/release/build/js/api/api.js";
|
|
153
159
|
|
|
154
160
|
// ============================================================================
|
|
155
161
|
// SolidJS-compatible Signal API
|
|
@@ -447,6 +453,9 @@ export function For<T>(props: ForProps<T>): any {
|
|
|
447
453
|
|
|
448
454
|
/**
|
|
449
455
|
* Show component for conditional rendering (SolidJS-style)
|
|
456
|
+
*
|
|
457
|
+
* The children function receives an accessor (getter function), not the raw value.
|
|
458
|
+
* This matches SolidJS behavior where you use: {(item) => <p>{item()}</p>}
|
|
450
459
|
*/
|
|
451
460
|
export function Show<T>(props: ShowProps<T>): any {
|
|
452
461
|
const { when, children } = props;
|
|
@@ -455,9 +464,13 @@ export function Show<T>(props: ShowProps<T>): any {
|
|
|
455
464
|
// Convert when to a getter if it's not already
|
|
456
465
|
const condition = typeof when === "function" ? when : () => when;
|
|
457
466
|
|
|
467
|
+
// Create a stable accessor for the condition value
|
|
468
|
+
// This matches SolidJS behavior where children receives an accessor
|
|
469
|
+
const valueAccessor = () => condition() as NonNullable<T>;
|
|
470
|
+
|
|
458
471
|
return show(
|
|
459
472
|
() => Boolean(condition()),
|
|
460
|
-
() => resolveChild(children,
|
|
473
|
+
() => resolveChild(children, valueAccessor)
|
|
461
474
|
);
|
|
462
475
|
}
|
|
463
476
|
|
|
@@ -564,17 +577,22 @@ export function Switch(props: SwitchProps): any {
|
|
|
564
577
|
|
|
565
578
|
/**
|
|
566
579
|
* Match component for use inside Switch (SolidJS-style)
|
|
580
|
+
*
|
|
581
|
+
* The children function receives an accessor (getter function), matching SolidJS.
|
|
567
582
|
*/
|
|
568
583
|
export function Match<T>(props: MatchProps<T>): { __isMatch: true; when: () => boolean; condition: () => T; children: () => any } {
|
|
569
584
|
const { when, children } = props;
|
|
570
585
|
const condition = typeof when === "function" ? when : () => when;
|
|
571
586
|
|
|
587
|
+
// Create a stable accessor for the condition value (SolidJS-style)
|
|
588
|
+
const valueAccessor = () => condition() as NonNullable<T>;
|
|
589
|
+
|
|
572
590
|
return {
|
|
573
591
|
__isMatch: true,
|
|
574
592
|
when: () => Boolean(condition()),
|
|
575
593
|
condition,
|
|
576
|
-
//
|
|
577
|
-
children: () => resolveChild(children,
|
|
594
|
+
// Pass accessor instead of raw value to match SolidJS behavior
|
|
595
|
+
children: () => resolveChild(children, valueAccessor),
|
|
578
596
|
};
|
|
579
597
|
}
|
|
580
598
|
|