@proyecto-viviana/solidaria-components 0.1.2 → 0.2.1

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 (62) 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.ssr.js +15 -15
  20. package/dist/index.ssr.js.map +2 -2
  21. package/package.json +8 -9
  22. package/src/Autocomplete.tsx +0 -174
  23. package/src/Breadcrumbs.tsx +0 -264
  24. package/src/Button.tsx +0 -238
  25. package/src/Calendar.tsx +0 -471
  26. package/src/Checkbox.tsx +0 -387
  27. package/src/Color.tsx +0 -1370
  28. package/src/ComboBox.tsx +0 -824
  29. package/src/DateField.tsx +0 -337
  30. package/src/DatePicker.tsx +0 -367
  31. package/src/Dialog.tsx +0 -262
  32. package/src/Disclosure.tsx +0 -439
  33. package/src/GridList.tsx +0 -511
  34. package/src/Landmark.tsx +0 -203
  35. package/src/Link.tsx +0 -201
  36. package/src/ListBox.tsx +0 -346
  37. package/src/Menu.tsx +0 -544
  38. package/src/Meter.tsx +0 -157
  39. package/src/Modal.tsx +0 -433
  40. package/src/NumberField.tsx +0 -542
  41. package/src/Popover.tsx +0 -540
  42. package/src/ProgressBar.tsx +0 -162
  43. package/src/RadioGroup.tsx +0 -356
  44. package/src/RangeCalendar.tsx +0 -462
  45. package/src/SearchField.tsx +0 -479
  46. package/src/Select.tsx +0 -734
  47. package/src/Separator.tsx +0 -130
  48. package/src/Slider.tsx +0 -500
  49. package/src/Switch.tsx +0 -213
  50. package/src/Table.tsx +0 -857
  51. package/src/Tabs.tsx +0 -552
  52. package/src/TagGroup.tsx +0 -421
  53. package/src/TextField.tsx +0 -271
  54. package/src/TimeField.tsx +0 -455
  55. package/src/Toast.tsx +0 -503
  56. package/src/Toolbar.tsx +0 -160
  57. package/src/Tooltip.tsx +0 -423
  58. package/src/Tree.tsx +0 -551
  59. package/src/VisuallyHidden.tsx +0 -60
  60. package/src/contexts.ts +0 -74
  61. package/src/index.ts +0 -620
  62. 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 };