@proyecto-viviana/solidaria-components 0.1.3 → 0.2.2

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
Files changed (64) hide show
  1. package/dist/Color.d.ts +6 -2
  2. package/dist/Color.d.ts.map +1 -1
  3. package/dist/ComboBox.d.ts +3 -3
  4. package/dist/ComboBox.d.ts.map +1 -1
  5. package/dist/GridList.d.ts +2 -2
  6. package/dist/GridList.d.ts.map +1 -1
  7. package/dist/ListBox.d.ts +5 -5
  8. package/dist/ListBox.d.ts.map +1 -1
  9. package/dist/Menu.d.ts +3 -3
  10. package/dist/Menu.d.ts.map +1 -1
  11. package/dist/Select.d.ts +3 -3
  12. package/dist/Select.d.ts.map +1 -1
  13. package/dist/Table.d.ts +2 -2
  14. package/dist/Table.d.ts.map +1 -1
  15. package/dist/Tabs.d.ts +1 -1
  16. package/dist/Tabs.d.ts.map +1 -1
  17. package/dist/index.js +15 -15
  18. package/dist/index.js.map +2 -2
  19. package/dist/index.jsx +9056 -0
  20. package/dist/index.jsx.map +7 -0
  21. package/dist/index.ssr.js +15 -15
  22. package/dist/index.ssr.js.map +2 -2
  23. package/package.json +8 -10
  24. package/src/Autocomplete.tsx +0 -174
  25. package/src/Breadcrumbs.tsx +0 -264
  26. package/src/Button.tsx +0 -238
  27. package/src/Calendar.tsx +0 -471
  28. package/src/Checkbox.tsx +0 -387
  29. package/src/Color.tsx +0 -1370
  30. package/src/ComboBox.tsx +0 -824
  31. package/src/DateField.tsx +0 -337
  32. package/src/DatePicker.tsx +0 -367
  33. package/src/Dialog.tsx +0 -262
  34. package/src/Disclosure.tsx +0 -439
  35. package/src/GridList.tsx +0 -511
  36. package/src/Landmark.tsx +0 -203
  37. package/src/Link.tsx +0 -201
  38. package/src/ListBox.tsx +0 -346
  39. package/src/Menu.tsx +0 -544
  40. package/src/Meter.tsx +0 -157
  41. package/src/Modal.tsx +0 -433
  42. package/src/NumberField.tsx +0 -542
  43. package/src/Popover.tsx +0 -540
  44. package/src/ProgressBar.tsx +0 -162
  45. package/src/RadioGroup.tsx +0 -356
  46. package/src/RangeCalendar.tsx +0 -462
  47. package/src/SearchField.tsx +0 -479
  48. package/src/Select.tsx +0 -734
  49. package/src/Separator.tsx +0 -130
  50. package/src/Slider.tsx +0 -500
  51. package/src/Switch.tsx +0 -213
  52. package/src/Table.tsx +0 -857
  53. package/src/Tabs.tsx +0 -552
  54. package/src/TagGroup.tsx +0 -421
  55. package/src/TextField.tsx +0 -271
  56. package/src/TimeField.tsx +0 -455
  57. package/src/Toast.tsx +0 -503
  58. package/src/Toolbar.tsx +0 -160
  59. package/src/Tooltip.tsx +0 -423
  60. package/src/Tree.tsx +0 -551
  61. package/src/VisuallyHidden.tsx +0 -60
  62. package/src/contexts.ts +0 -74
  63. package/src/index.ts +0 -620
  64. package/src/utils.tsx +0 -329
package/src/Tooltip.tsx DELETED
@@ -1,423 +0,0 @@
1
- /**
2
- * Tooltip component for solidaria-components
3
- *
4
- * A tooltip displays a description of an element on hover or focus.
5
- * Port of react-aria-components/src/Tooltip.tsx
6
- */
7
-
8
- import {
9
- type JSX,
10
- type ParentComponent,
11
- createContext,
12
- useContext,
13
- createMemo,
14
- createSignal,
15
- createEffect,
16
- onCleanup,
17
- Show,
18
- } from 'solid-js';
19
- import { isServer } from 'solid-js/web';
20
- import {
21
- createTooltipTriggerState,
22
- type TooltipTriggerState,
23
- type TooltipTriggerProps as StateProps,
24
- } from '@proyecto-viviana/solid-stately';
25
- import {
26
- createTooltip,
27
- createTooltipTrigger,
28
- type TooltipTriggerProps as AriaProps,
29
- OverlayContainer,
30
- } from '@proyecto-viviana/solidaria';
31
- import {
32
- type RenderChildren,
33
- type ClassNameOrFunction,
34
- type StyleOrFunction,
35
- type SlotProps,
36
- useRenderProps,
37
- filterDOMProps,
38
- } from './utils';
39
-
40
- // ============================================
41
- // TYPES
42
- // ============================================
43
-
44
- export interface TooltipRenderProps {
45
- /** Whether the tooltip is currently entering (for animations). */
46
- isEntering: boolean;
47
- /** Whether the tooltip is currently exiting (for animations). */
48
- isExiting: boolean;
49
- /** The placement of the tooltip relative to the trigger. */
50
- placement: 'top' | 'bottom' | 'left' | 'right' | null;
51
- }
52
-
53
- export interface TooltipTriggerComponentProps extends StateProps, AriaProps {
54
- /** The children of the tooltip trigger (trigger element and tooltip). */
55
- children: JSX.Element;
56
- }
57
-
58
- export interface TooltipProps extends SlotProps {
59
- /** The children of the tooltip. A function may be provided to receive render props. */
60
- children?: RenderChildren<TooltipRenderProps>;
61
- /** The CSS className for the element. */
62
- class?: ClassNameOrFunction<TooltipRenderProps>;
63
- /** The inline style for the element. */
64
- style?: StyleOrFunction<TooltipRenderProps>;
65
- /** Whether the tooltip is open (controlled). */
66
- isOpen?: boolean;
67
- /** Whether the tooltip is open by default (uncontrolled). */
68
- defaultOpen?: boolean;
69
- /** The placement of the tooltip relative to the trigger. */
70
- placement?: 'top' | 'bottom' | 'left' | 'right';
71
- /** Whether to render the tooltip in a portal. */
72
- shouldFlip?: boolean;
73
- }
74
-
75
- // ============================================
76
- // CONTEXT
77
- // ============================================
78
-
79
- interface TooltipTriggerContextValue {
80
- state: TooltipTriggerState;
81
- tooltipProps: { id: string };
82
- triggerRef: () => HTMLElement | null | undefined;
83
- }
84
-
85
- const TooltipTriggerContext = createContext<TooltipTriggerContextValue | null>(null);
86
-
87
- // ============================================
88
- // COMPONENTS
89
- // ============================================
90
-
91
- /**
92
- * TooltipTrigger wraps around a trigger element and a Tooltip.
93
- * It handles opening and closing the Tooltip when the user hovers
94
- * over or focuses the trigger.
95
- *
96
- * @example
97
- * ```tsx
98
- * <TooltipTrigger>
99
- * <Button>Hover me</Button>
100
- * <Tooltip>This is a tooltip</Tooltip>
101
- * </TooltipTrigger>
102
- * ```
103
- */
104
- export const TooltipTrigger: ParentComponent<TooltipTriggerComponentProps> = (props) => {
105
- let triggerRef: HTMLElement | null = null;
106
-
107
- const state = createTooltipTriggerState({
108
- get delay() { return props.delay; },
109
- get closeDelay() { return props.closeDelay; },
110
- get isOpen() { return props.isOpen; },
111
- get defaultOpen() { return props.defaultOpen; },
112
- get onOpenChange() { return props.onOpenChange; },
113
- });
114
-
115
- const { triggerProps, tooltipProps } = createTooltipTrigger(
116
- {
117
- get isDisabled() { return props.isDisabled; },
118
- get trigger() { return props.trigger; },
119
- get shouldCloseOnPress() { return props.shouldCloseOnPress; },
120
- },
121
- state,
122
- () => triggerRef
123
- );
124
-
125
- const context: TooltipTriggerContextValue = {
126
- state,
127
- tooltipProps,
128
- triggerRef: () => triggerRef,
129
- };
130
-
131
- // Clone children and inject trigger props into the first child
132
- const processChildren = () => {
133
- const children = props.children;
134
- if (Array.isArray(children)) {
135
- // First child is the trigger, rest are tooltip(s)
136
- const [trigger, ...rest] = children;
137
- return (
138
- <>
139
- <TriggerWrapper
140
- triggerProps={triggerProps}
141
- ref={(el) => { triggerRef = el; }}
142
- >
143
- {trigger}
144
- </TriggerWrapper>
145
- {rest}
146
- </>
147
- );
148
- }
149
- return children;
150
- };
151
-
152
- return (
153
- <TooltipTriggerContext.Provider value={context}>
154
- {processChildren()}
155
- </TooltipTriggerContext.Provider>
156
- );
157
- };
158
-
159
- /**
160
- * Wrapper component that spreads trigger props onto its child
161
- */
162
- const TriggerWrapper: ParentComponent<{
163
- triggerProps: JSX.HTMLAttributes<HTMLElement>;
164
- ref: (el: HTMLElement) => void;
165
- }> = (props) => {
166
- // Get the child element and clone it with trigger props
167
- const child = () => props.children as JSX.Element;
168
-
169
- // We wrap in a span with display:contents to not affect layout.
170
- // However, display:contents makes getBoundingClientRect return zeros,
171
- // so we pass a ref callback that finds the first actual element child.
172
- const handleRef = (span: HTMLSpanElement) => {
173
- // Find the first element child that has dimensions (not display:contents)
174
- const findVisibleChild = (el: Element): HTMLElement | null => {
175
- if (el instanceof HTMLElement) {
176
- const rect = el.getBoundingClientRect();
177
- if (rect.width > 0 && rect.height > 0) {
178
- return el;
179
- }
180
- // Check children
181
- for (const child of el.children) {
182
- const found = findVisibleChild(child);
183
- if (found) return found;
184
- }
185
- }
186
- return null;
187
- };
188
-
189
- // Use requestAnimationFrame to ensure children are rendered and have dimensions
190
- // This is necessary because SolidJS may not have computed child layout yet
191
- const resolveRef = () => {
192
- const visibleChild = findVisibleChild(span);
193
- if (visibleChild) {
194
- props.ref(visibleChild);
195
- } else {
196
- // Fallback to span itself
197
- props.ref(span);
198
- }
199
- };
200
-
201
- // Try immediately first (in case layout is already computed)
202
- const immediateChild = findVisibleChild(span);
203
- if (immediateChild) {
204
- props.ref(immediateChild);
205
- } else {
206
- // Defer to next frame when layout should be computed
207
- requestAnimationFrame(resolveRef);
208
- }
209
- };
210
-
211
- return (
212
- <span
213
- {...props.triggerProps}
214
- ref={handleRef}
215
- style={{ display: 'contents' }}
216
- >
217
- {child()}
218
- </span>
219
- );
220
- };
221
-
222
- /**
223
- * A tooltip displays a description of an element on hover or focus.
224
- *
225
- * @example
226
- * ```tsx
227
- * <TooltipTrigger>
228
- * <Button>Hover me</Button>
229
- * <Tooltip>This is helpful information</Tooltip>
230
- * </TooltipTrigger>
231
- * ```
232
- */
233
- export function Tooltip(props: TooltipProps): JSX.Element {
234
- const context = useContext(TooltipTriggerContext);
235
-
236
- // Support standalone usage
237
- const localState = createTooltipTriggerState({
238
- get isOpen() { return props.isOpen; },
239
- get defaultOpen() { return props.defaultOpen; },
240
- });
241
-
242
- const state = () => context?.state ?? localState;
243
- const placement = () => props.placement ?? 'top';
244
-
245
- // Only render when open
246
- const isOpen = () => state().isOpen();
247
-
248
- return (
249
- <Show when={isOpen()}>
250
- <TooltipContent
251
- {...props}
252
- state={state()}
253
- contextTooltipProps={context?.tooltipProps ?? {}}
254
- placement={placement()}
255
- triggerRef={context?.triggerRef ?? (() => null)}
256
- />
257
- </Show>
258
- );
259
- }
260
-
261
- /**
262
- * Internal component that renders the tooltip content
263
- */
264
- function TooltipContent(
265
- props: TooltipProps & {
266
- state: TooltipTriggerState;
267
- contextTooltipProps: { id?: string };
268
- placement: 'top' | 'bottom' | 'left' | 'right';
269
- triggerRef: () => HTMLElement | null | undefined;
270
- }
271
- ): JSX.Element {
272
- if (isServer) {
273
- return null as unknown as JSX.Element;
274
- }
275
-
276
- let tooltipRef!: HTMLDivElement;
277
- const { tooltipProps: ariaTooltipProps } = createTooltip({}, props.state);
278
-
279
- // Signal to track position styles
280
- // Start visible at 0,0 and update position asynchronously
281
- // This ensures the tooltip is immediately accessible (for screen readers and tests)
282
- // while the visual position gets calculated
283
- const [positionStyles, setPositionStyles] = createSignal({
284
- top: '0px',
285
- left: '0px',
286
- visibility: 'visible' as 'hidden' | 'visible',
287
- });
288
-
289
- const values = createMemo<TooltipRenderProps>(() => ({
290
- isEntering: false, // TODO: animation support
291
- isExiting: false,
292
- placement: props.placement,
293
- }));
294
-
295
- const renderProps = useRenderProps(
296
- {
297
- class: props.class,
298
- style: props.style,
299
- children: props.children,
300
- defaultClassName: 'solidaria-Tooltip',
301
- },
302
- values
303
- );
304
-
305
- // Calculate position based on trigger element
306
- // Using position: fixed so we use viewport coordinates directly from getBoundingClientRect
307
- // Returns true if position was successfully updated, false if we need to retry
308
- const updatePosition = (): boolean => {
309
- const triggerEl = props.triggerRef();
310
- if (!triggerEl || !tooltipRef) return false;
311
-
312
- const triggerRect = triggerEl.getBoundingClientRect();
313
-
314
- // Check if the trigger has valid dimensions (not display:contents or not rendered yet)
315
- if (triggerRect.width === 0 || triggerRect.height === 0) {
316
- return false; // Need to retry
317
- }
318
-
319
- // Use offsetWidth/offsetHeight which are more reliable than getBoundingClientRect
320
- // when the element might be positioned off-screen initially
321
- const tooltipWidth = tooltipRef.offsetWidth;
322
- const tooltipHeight = tooltipRef.offsetHeight;
323
- const offset = 8; // Gap between trigger and tooltip
324
-
325
- let top = 0;
326
- let left = 0;
327
-
328
- // Using viewport coordinates for position: fixed
329
- switch (props.placement) {
330
- case 'top':
331
- top = triggerRect.top - tooltipHeight - offset;
332
- left = triggerRect.left + (triggerRect.width - tooltipWidth) / 2;
333
- break;
334
- case 'bottom':
335
- top = triggerRect.bottom + offset;
336
- left = triggerRect.left + (triggerRect.width - tooltipWidth) / 2;
337
- break;
338
- case 'left':
339
- top = triggerRect.top + (triggerRect.height - tooltipHeight) / 2;
340
- left = triggerRect.left - tooltipWidth - offset;
341
- break;
342
- case 'right':
343
- top = triggerRect.top + (triggerRect.height - tooltipHeight) / 2;
344
- left = triggerRect.right + offset;
345
- break;
346
- }
347
-
348
- setPositionStyles({
349
- top: `${top}px`,
350
- left: `${left}px`,
351
- visibility: 'visible',
352
- });
353
-
354
- return true;
355
- };
356
-
357
- // Set up positioning effect - runs when trigger ref is available
358
- createEffect(() => {
359
- const trigger = props.triggerRef();
360
- if (!trigger) return;
361
-
362
- // Initial position calculation - use requestAnimationFrame to ensure
363
- // the element is rendered and has proper dimensions
364
- // We may need multiple frames if the trigger ref hasn't resolved yet
365
- let retryCount = 0;
366
- const maxRetries = 5;
367
-
368
- const tryUpdatePosition = () => {
369
- const success = updatePosition();
370
- if (!success && retryCount < maxRetries) {
371
- retryCount++;
372
- // In JSDOM, requestAnimationFrame may not trigger layout properly
373
- // Use setTimeout for more reliable deferral across environments
374
- setTimeout(tryUpdatePosition, 16); // ~60fps
375
- }
376
- // If all retries fail, tooltip stays at 0,0 (test environments)
377
- // The tooltip is visible by default, so it remains accessible
378
- };
379
-
380
- // Initial attempt - use rAF for real browsers, then fall back to timeout retries
381
- requestAnimationFrame(tryUpdatePosition);
382
-
383
- // Update on scroll/resize
384
- window.addEventListener('scroll', updatePosition, true);
385
- window.addEventListener('resize', updatePosition);
386
-
387
- onCleanup(() => {
388
- window.removeEventListener('scroll', updatePosition, true);
389
- window.removeEventListener('resize', updatePosition);
390
- });
391
- });
392
-
393
- // Filter to only valid DOM props (aria-*, data-*, events)
394
- const domProps = filterDOMProps(props);
395
-
396
- // Extract ref from ariaTooltipProps to avoid type conflicts (SolidJS ref types are element-specific)
397
- const { ref: _ariaRef, ...cleanAriaProps } = ariaTooltipProps as Record<string, unknown>;
398
-
399
- return (
400
- <OverlayContainer>
401
- <div
402
- {...domProps}
403
- {...props.contextTooltipProps}
404
- {...cleanAriaProps}
405
- role="tooltip"
406
- ref={tooltipRef}
407
- class={renderProps.class()}
408
- style={{
409
- position: 'fixed',
410
- 'z-index': 100000,
411
- ...positionStyles(),
412
- ...renderProps.style(),
413
- }}
414
- data-placement={props.placement}
415
- >
416
- {renderProps.renderChildren()}
417
- </div>
418
- </OverlayContainer>
419
- );
420
- }
421
-
422
- // Re-export types
423
- export type { TooltipTriggerState };