@fpkit/acss 1.0.0-beta.1 → 2.0.0

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 (103) hide show
  1. package/README.md +92 -0
  2. package/docs/README.md +325 -0
  3. package/docs/guides/accessibility.md +764 -0
  4. package/docs/guides/architecture.md +705 -0
  5. package/docs/guides/composition.md +688 -0
  6. package/docs/guides/css-variables.md +522 -0
  7. package/docs/guides/storybook.md +828 -0
  8. package/docs/guides/testing.md +817 -0
  9. package/docs/testing/focus-indicator-testing.md +437 -0
  10. package/libs/{chunk-7XPFW7CB.js → chunk-43TK2ICH.js} +2 -2
  11. package/libs/chunk-5PJYLVFY.cjs +17 -0
  12. package/libs/chunk-5PJYLVFY.cjs.map +1 -0
  13. package/libs/chunk-E4OSROCA.cjs +17 -0
  14. package/libs/chunk-E4OSROCA.cjs.map +1 -0
  15. package/libs/chunk-KVKQLRJG.js +10 -0
  16. package/libs/chunk-KVKQLRJG.js.map +1 -0
  17. package/libs/{chunk-QVW6W76L.cjs → chunk-MGPWZRBX.cjs} +3 -3
  18. package/libs/chunk-NNTBIHSD.js +8 -0
  19. package/libs/chunk-NNTBIHSD.js.map +1 -0
  20. package/libs/{chunk-X3JCTEPD.js → chunk-QKHPHMG2.js} +2 -2
  21. package/libs/{chunk-T4T6GWYQ.cjs → chunk-R7NLLZU2.cjs} +3 -3
  22. package/libs/{chunk-X5LGFCWG.js → chunk-UJAQVHWC.js} +3 -3
  23. package/libs/{chunk-DKTHCQ5P.cjs → chunk-X5RKCLDC.cjs} +3 -3
  24. package/libs/components/breadcrumbs/breadcrumb.cjs +5 -5
  25. package/libs/components/breadcrumbs/breadcrumb.d.cts +1 -1
  26. package/libs/components/breadcrumbs/breadcrumb.d.ts +1 -1
  27. package/libs/components/breadcrumbs/breadcrumb.js +2 -2
  28. package/libs/components/button.cjs +3 -3
  29. package/libs/components/button.d.cts +1 -1
  30. package/libs/components/button.d.ts +1 -1
  31. package/libs/components/button.js +1 -1
  32. package/libs/components/buttons/button.css +1 -1
  33. package/libs/components/buttons/button.css.map +1 -1
  34. package/libs/components/buttons/button.min.css +2 -2
  35. package/libs/components/dialog/dialog.cjs +4 -4
  36. package/libs/components/dialog/dialog.js +2 -2
  37. package/libs/components/icons/icon.d.cts +32 -32
  38. package/libs/components/icons/icon.d.ts +32 -32
  39. package/libs/components/link/link.cjs +11 -3
  40. package/libs/components/link/link.d.cts +131 -3
  41. package/libs/components/link/link.d.ts +131 -3
  42. package/libs/components/link/link.js +1 -1
  43. package/libs/components/list/list.css +1 -1
  44. package/libs/components/list/list.min.css +1 -1
  45. package/libs/components/modal.cjs +3 -3
  46. package/libs/components/modal.js +2 -2
  47. package/libs/hooks.cjs +3 -3
  48. package/libs/hooks.d.cts +1 -1
  49. package/libs/hooks.d.ts +1 -1
  50. package/libs/hooks.js +2 -2
  51. package/libs/index.cjs +12 -12
  52. package/libs/index.css +1 -1
  53. package/libs/index.css.map +1 -1
  54. package/libs/index.d.cts +237 -2
  55. package/libs/index.d.ts +237 -2
  56. package/libs/index.js +5 -5
  57. package/package.json +4 -3
  58. package/src/components/README.mdx +1 -1
  59. package/src/components/breadcrumbs/breadcrumb.test.tsx +1 -2
  60. package/src/components/buttons/README.mdx +19 -9
  61. package/src/components/buttons/button.scss +5 -0
  62. package/src/components/buttons/button.stories.tsx +8 -5
  63. package/src/components/buttons/button.tsx +19 -15
  64. package/src/components/cards/card.stories.tsx +1 -1
  65. package/src/components/details/details.stories.tsx +1 -1
  66. package/src/components/form/form.stories.tsx +1 -1
  67. package/src/components/form/input.stories.tsx +1 -1
  68. package/src/components/form/select.stories.tsx +1 -1
  69. package/src/components/heading/README.mdx +292 -0
  70. package/src/components/icons/icon.stories.tsx +1 -1
  71. package/src/components/link/link.stories.tsx +205 -8
  72. package/src/components/link/link.test.tsx +1 -1
  73. package/src/components/link/link.tsx +22 -0
  74. package/src/components/link/link.types.ts +11 -3
  75. package/src/components/list/list.scss +1 -1
  76. package/src/components/nav/nav.stories.tsx +1 -1
  77. package/src/components/ui.stories.tsx +53 -19
  78. package/src/docs/accessibility.mdx +484 -0
  79. package/src/docs/composition.mdx +549 -0
  80. package/src/docs/css-variables.mdx +380 -0
  81. package/src/docs/fpkit-developer.mdx +623 -0
  82. package/src/introduction.mdx +356 -0
  83. package/src/styles/buttons/button.css +4 -0
  84. package/src/styles/buttons/button.css.map +1 -1
  85. package/src/styles/index.css +9 -3
  86. package/src/styles/index.css.map +1 -1
  87. package/src/styles/list/list.css +1 -1
  88. package/src/styles/utilities/_disabled.scss +5 -4
  89. package/libs/chunk-33PNJ4LO.cjs +0 -15
  90. package/libs/chunk-33PNJ4LO.cjs.map +0 -1
  91. package/libs/chunk-GT77BX4L.cjs +0 -17
  92. package/libs/chunk-GT77BX4L.cjs.map +0 -1
  93. package/libs/chunk-OVWLQYMK.js +0 -10
  94. package/libs/chunk-OVWLQYMK.js.map +0 -1
  95. package/libs/chunk-UEPAWMDF.js +0 -8
  96. package/libs/chunk-UEPAWMDF.js.map +0 -1
  97. package/libs/link-5192f411.d.ts +0 -323
  98. /package/libs/{chunk-7XPFW7CB.js.map → chunk-43TK2ICH.js.map} +0 -0
  99. /package/libs/{chunk-QVW6W76L.cjs.map → chunk-MGPWZRBX.cjs.map} +0 -0
  100. /package/libs/{chunk-X3JCTEPD.js.map → chunk-QKHPHMG2.js.map} +0 -0
  101. /package/libs/{chunk-T4T6GWYQ.cjs.map → chunk-R7NLLZU2.cjs.map} +0 -0
  102. /package/libs/{chunk-X5LGFCWG.js.map → chunk-UJAQVHWC.js.map} +0 -0
  103. /package/libs/{chunk-DKTHCQ5P.cjs.map → chunk-X5RKCLDC.cjs.map} +0 -0
package/libs/index.d.cts CHANGED
@@ -4,7 +4,7 @@ export { default as Field, FieldProps } from './components/form/fields.cjs';
4
4
  export { default as Input } from './components/form/inputs.cjs';
5
5
  export { default as Icon, IconProps } from './components/icons/icon.cjs';
6
6
  import React, { ReactNode } from 'react';
7
- export { L as Link, a as LinkProps, L as To } from './link-5192f411.js';
7
+ export { default as Link, default as To } from './components/link/link.cjs';
8
8
  export { List } from './components/list/list.cjs';
9
9
  export { Modal, ModalProps } from './components/modal.cjs';
10
10
  export { default as Popover, PopoverProps } from './components/popover/popover.cjs';
@@ -328,6 +328,241 @@ declare const Img: {
328
328
  displayName: string;
329
329
  };
330
330
 
331
+ /**
332
+ * Props for the Link component.
333
+ *
334
+ * The Link component renders accessible anchor elements with enhanced security,
335
+ * styling variants, and WCAG 2.1 AA compliance. It supports both traditional
336
+ * text links and button-styled links for call-to-action scenarios.
337
+ *
338
+ * ## Accessibility Considerations
339
+ *
340
+ * - External links automatically include `rel="noopener noreferrer"` for security
341
+ * - Links should have descriptive text or `aria-label` for screen readers
342
+ * - Focus indicators must meet WCAG 2.4.7 contrast requirements (3:1 minimum)
343
+ * - Button-styled links maintain semantic `<a>` element for proper navigation
344
+ *
345
+ * @example
346
+ * ```tsx
347
+ * // Basic link
348
+ * <Link href="/about">About Us</Link>
349
+ *
350
+ * // External link with prefetch
351
+ * <Link href="https://example.com" target="_blank" prefetch>
352
+ * Visit Example
353
+ * </Link>
354
+ *
355
+ * // Button-styled link
356
+ * <Link href="/signup" btnStyle="primary">
357
+ * <b>Sign Up Now</b>
358
+ * </Link>
359
+ * ```
360
+ */
361
+ type LinkProps = {
362
+ /**
363
+ * The URL that the hyperlink points to.
364
+ * Can be relative or absolute, internal or external.
365
+ *
366
+ * @example
367
+ * ```tsx
368
+ * href="/products"
369
+ * href="https://example.com"
370
+ * href="mailto:hello@example.com"
371
+ * href="tel:+1234567890"
372
+ * ```
373
+ */
374
+ href?: string;
375
+ /**
376
+ * Where to display the linked URL.
377
+ *
378
+ * - `_self` (default): Current browsing context
379
+ * - `_blank`: New tab/window (automatically adds security attributes)
380
+ * - `_parent`: Parent browsing context
381
+ * - `_top`: Top-level browsing context
382
+ *
383
+ * Note: When `target="_blank"`, `rel="noopener noreferrer"` is automatically
384
+ * added for security unless explicitly overridden.
385
+ *
386
+ * @example
387
+ * ```tsx
388
+ * target="_blank" // Opens in new tab with security
389
+ * ```
390
+ */
391
+ target?: string;
392
+ /**
393
+ * Relationship between current document and linked URL.
394
+ *
395
+ * Common values:
396
+ * - `noopener`: Prevents window.opener access (security)
397
+ * - `noreferrer`: Prevents referrer header (privacy)
398
+ * - `nofollow`: Hints search engines not to follow (SEO)
399
+ * - `prefetch`: Hints to prefetch the resource (performance)
400
+ *
401
+ * Note: For `target="_blank"`, this component automatically merges
402
+ * `noopener noreferrer` with any user-provided values for security.
403
+ *
404
+ * @example
405
+ * ```tsx
406
+ * rel="nofollow noopener"
407
+ * rel="author"
408
+ * ```
409
+ */
410
+ rel?: string;
411
+ /**
412
+ * Content to display inside the link.
413
+ *
414
+ * For accessibility, ensure link text is descriptive and meaningful.
415
+ * Avoid generic text like "click here" or "read more" without context.
416
+ *
417
+ * @example
418
+ * ```tsx
419
+ * // ✅ Good: Descriptive link text
420
+ * <Link href="/products">View all products</Link>
421
+ *
422
+ * // ❌ Bad: Generic link text without context
423
+ * <Link href="/products">Click here</Link>
424
+ *
425
+ * // ✅ Good: Icon with accessible label
426
+ * <Link href="/home" aria-label="Return to homepage">
427
+ * <HomeIcon aria-hidden="true" />
428
+ * </Link>
429
+ * ```
430
+ */
431
+ children: React.ReactNode;
432
+ /**
433
+ * Inline CSS styles to apply to the link element.
434
+ * Can be used to override CSS custom properties.
435
+ *
436
+ * @example
437
+ * ```tsx
438
+ * styles={{
439
+ * '--link-color': '#ff0000',
440
+ * '--link-decoration': 'underline',
441
+ * }}
442
+ * ```
443
+ */
444
+ styles?: React.CSSProperties;
445
+ /**
446
+ * Hints to the browser to prefetch the linked resource.
447
+ *
448
+ * When `true` and `target="_blank"`, adds `rel="prefetch"` along with
449
+ * security attributes. This can improve perceived performance but should
450
+ * be used judiciously as it consumes bandwidth.
451
+ *
452
+ * Note: Browser support varies. Modern browsers may ignore this hint.
453
+ *
454
+ * @default false
455
+ * @example
456
+ * ```tsx
457
+ * <Link href="/next-page" prefetch>Next Page</Link>
458
+ * ```
459
+ */
460
+ prefetch?: boolean;
461
+ /**
462
+ * Applies button-like styling to the link.
463
+ *
464
+ * When set, the link renders with button styling including padding,
465
+ * borders, and hover effects while maintaining semantic anchor behavior.
466
+ *
467
+ * Common values:
468
+ * - `"btn"`: Standard button styling
469
+ * - `"pill"`: Rounded pill button styling
470
+ *
471
+ * Alternative: Wrap children in `<b>` or `<i>` tags for automatic styling:
472
+ * - `<b>`: Applies button styling
473
+ * - `<i>`: Applies pill styling
474
+ *
475
+ * @example
476
+ * ```tsx
477
+ * // Using btnStyle prop
478
+ * <Link href="/signup" btnStyle="btn">Sign Up</Link>
479
+ *
480
+ * // Using child wrapper (automatic detection)
481
+ * <Link href="/signup"><b>Sign Up</b></Link>
482
+ * <Link href="/signup"><i>Pill Button</i></Link>
483
+ * ```
484
+ */
485
+ btnStyle?: string;
486
+ /**
487
+ * Event handler called when the link is clicked or activated.
488
+ *
489
+ * **Recommended for most use cases**, especially analytics and tracking.
490
+ * This event fires for:
491
+ * - Mouse clicks
492
+ * - Touch/tap interactions
493
+ * - Keyboard activation (Enter key)
494
+ * - Assistive technology activation
495
+ *
496
+ * Use `onClick` when you need to track ALL user activations, including
497
+ * keyboard users. This ensures full accessibility coverage.
498
+ *
499
+ * @param event - The mouse event
500
+ * @example
501
+ * ```tsx
502
+ * // ✅ RECOMMENDED: onClick tracks all activation methods
503
+ * <Link
504
+ * href="/products"
505
+ * onClick={(e) => {
506
+ * trackEvent('link_click', { href: '/products' });
507
+ * }}
508
+ * >
509
+ * Products
510
+ * </Link>
511
+ * ```
512
+ */
513
+ onClick?: (event: React.MouseEvent<HTMLAnchorElement>) => void;
514
+ /**
515
+ * Event handler called when a pointer device button is pressed on the link.
516
+ *
517
+ * Use this for specific pointer interactions like:
518
+ * - Drag-and-drop detection
519
+ * - Touch gesture recognition
520
+ * - Distinguishing input types (mouse vs touch vs pen)
521
+ * - Providing early visual feedback before click completes
522
+ *
523
+ * **⚠️ Accessibility Note**: Unlike `onClick`, this does NOT fire for
524
+ * keyboard activation (Enter key). If you need to track all user interactions
525
+ * including keyboard users, use `onClick` instead.
526
+ *
527
+ * @param event - The pointer event
528
+ * @example
529
+ * ```tsx
530
+ * // Use onPointerDown for pointer-specific interactions
531
+ * <Link
532
+ * href="/products"
533
+ * onPointerDown={(e) => {
534
+ * // Distinguish between mouse (2), touch (5), and pen (3)
535
+ * console.log('Pointer type:', e.pointerType);
536
+ * }}
537
+ * >
538
+ * Products
539
+ * </Link>
540
+ * ```
541
+ *
542
+ * @example
543
+ * ```tsx
544
+ * // ✅ Use both handlers together for comprehensive tracking
545
+ * <Link
546
+ * href="/products"
547
+ * onClick={(e) => trackAllActivations(e)}
548
+ * onPointerDown={(e) => provideFeedback(e)}
549
+ * >
550
+ * Products
551
+ * </Link>
552
+ * ```
553
+ */
554
+ onPointerDown?: (event: React.PointerEvent<HTMLAnchorElement>) => void;
555
+ /**
556
+ * Icon element to display in the link (used by IconLink).
557
+ *
558
+ * @example
559
+ * ```tsx
560
+ * <IconLink href="/home" icon={<HomeIcon />} />
561
+ * ```
562
+ */
563
+ icon?: React.ReactNode;
564
+ } & Omit<React.ComponentPropsWithoutRef<"a">, 'style'>;
565
+
331
566
  /**
332
567
  * Props for the TextToSpeechComponent.
333
568
  * @interface TextToSpeechComponentProps
@@ -955,4 +1190,4 @@ type FPComponent = {
955
1190
  */
956
1191
  declare const FP: FPComponent;
957
1192
 
958
- export { Article, Aside, Badge, BadgeProps, FP as Box, Caption, ComponentProps$1 as ComponentProps, Details, FP, Footer, Header, Img, ImgProps, Landmarks, Main, Section, Table, Tag, TagProps, TagVariant, Tbody, Td, TextToSpeech, Thead, Tr };
1193
+ export { Article, Aside, Badge, BadgeProps, FP as Box, Caption, ComponentProps$1 as ComponentProps, Details, FP, Footer, Header, Img, ImgProps, Landmarks, LinkProps, Main, Section, Table, Tag, TagProps, TagVariant, Tbody, Td, TextToSpeech, Thead, Tr };
package/libs/index.d.ts CHANGED
@@ -4,7 +4,7 @@ export { default as Field, FieldProps } from './components/form/fields.js';
4
4
  export { default as Input } from './components/form/inputs.js';
5
5
  export { default as Icon, IconProps } from './components/icons/icon.js';
6
6
  import React, { ReactNode } from 'react';
7
- export { L as Link, a as LinkProps, L as To } from './link-5192f411.js';
7
+ export { default as Link, default as To } from './components/link/link.js';
8
8
  export { List } from './components/list/list.js';
9
9
  export { Modal, ModalProps } from './components/modal.js';
10
10
  export { default as Popover, PopoverProps } from './components/popover/popover.js';
@@ -328,6 +328,241 @@ declare const Img: {
328
328
  displayName: string;
329
329
  };
330
330
 
331
+ /**
332
+ * Props for the Link component.
333
+ *
334
+ * The Link component renders accessible anchor elements with enhanced security,
335
+ * styling variants, and WCAG 2.1 AA compliance. It supports both traditional
336
+ * text links and button-styled links for call-to-action scenarios.
337
+ *
338
+ * ## Accessibility Considerations
339
+ *
340
+ * - External links automatically include `rel="noopener noreferrer"` for security
341
+ * - Links should have descriptive text or `aria-label` for screen readers
342
+ * - Focus indicators must meet WCAG 2.4.7 contrast requirements (3:1 minimum)
343
+ * - Button-styled links maintain semantic `<a>` element for proper navigation
344
+ *
345
+ * @example
346
+ * ```tsx
347
+ * // Basic link
348
+ * <Link href="/about">About Us</Link>
349
+ *
350
+ * // External link with prefetch
351
+ * <Link href="https://example.com" target="_blank" prefetch>
352
+ * Visit Example
353
+ * </Link>
354
+ *
355
+ * // Button-styled link
356
+ * <Link href="/signup" btnStyle="primary">
357
+ * <b>Sign Up Now</b>
358
+ * </Link>
359
+ * ```
360
+ */
361
+ type LinkProps = {
362
+ /**
363
+ * The URL that the hyperlink points to.
364
+ * Can be relative or absolute, internal or external.
365
+ *
366
+ * @example
367
+ * ```tsx
368
+ * href="/products"
369
+ * href="https://example.com"
370
+ * href="mailto:hello@example.com"
371
+ * href="tel:+1234567890"
372
+ * ```
373
+ */
374
+ href?: string;
375
+ /**
376
+ * Where to display the linked URL.
377
+ *
378
+ * - `_self` (default): Current browsing context
379
+ * - `_blank`: New tab/window (automatically adds security attributes)
380
+ * - `_parent`: Parent browsing context
381
+ * - `_top`: Top-level browsing context
382
+ *
383
+ * Note: When `target="_blank"`, `rel="noopener noreferrer"` is automatically
384
+ * added for security unless explicitly overridden.
385
+ *
386
+ * @example
387
+ * ```tsx
388
+ * target="_blank" // Opens in new tab with security
389
+ * ```
390
+ */
391
+ target?: string;
392
+ /**
393
+ * Relationship between current document and linked URL.
394
+ *
395
+ * Common values:
396
+ * - `noopener`: Prevents window.opener access (security)
397
+ * - `noreferrer`: Prevents referrer header (privacy)
398
+ * - `nofollow`: Hints search engines not to follow (SEO)
399
+ * - `prefetch`: Hints to prefetch the resource (performance)
400
+ *
401
+ * Note: For `target="_blank"`, this component automatically merges
402
+ * `noopener noreferrer` with any user-provided values for security.
403
+ *
404
+ * @example
405
+ * ```tsx
406
+ * rel="nofollow noopener"
407
+ * rel="author"
408
+ * ```
409
+ */
410
+ rel?: string;
411
+ /**
412
+ * Content to display inside the link.
413
+ *
414
+ * For accessibility, ensure link text is descriptive and meaningful.
415
+ * Avoid generic text like "click here" or "read more" without context.
416
+ *
417
+ * @example
418
+ * ```tsx
419
+ * // ✅ Good: Descriptive link text
420
+ * <Link href="/products">View all products</Link>
421
+ *
422
+ * // ❌ Bad: Generic link text without context
423
+ * <Link href="/products">Click here</Link>
424
+ *
425
+ * // ✅ Good: Icon with accessible label
426
+ * <Link href="/home" aria-label="Return to homepage">
427
+ * <HomeIcon aria-hidden="true" />
428
+ * </Link>
429
+ * ```
430
+ */
431
+ children: React.ReactNode;
432
+ /**
433
+ * Inline CSS styles to apply to the link element.
434
+ * Can be used to override CSS custom properties.
435
+ *
436
+ * @example
437
+ * ```tsx
438
+ * styles={{
439
+ * '--link-color': '#ff0000',
440
+ * '--link-decoration': 'underline',
441
+ * }}
442
+ * ```
443
+ */
444
+ styles?: React.CSSProperties;
445
+ /**
446
+ * Hints to the browser to prefetch the linked resource.
447
+ *
448
+ * When `true` and `target="_blank"`, adds `rel="prefetch"` along with
449
+ * security attributes. This can improve perceived performance but should
450
+ * be used judiciously as it consumes bandwidth.
451
+ *
452
+ * Note: Browser support varies. Modern browsers may ignore this hint.
453
+ *
454
+ * @default false
455
+ * @example
456
+ * ```tsx
457
+ * <Link href="/next-page" prefetch>Next Page</Link>
458
+ * ```
459
+ */
460
+ prefetch?: boolean;
461
+ /**
462
+ * Applies button-like styling to the link.
463
+ *
464
+ * When set, the link renders with button styling including padding,
465
+ * borders, and hover effects while maintaining semantic anchor behavior.
466
+ *
467
+ * Common values:
468
+ * - `"btn"`: Standard button styling
469
+ * - `"pill"`: Rounded pill button styling
470
+ *
471
+ * Alternative: Wrap children in `<b>` or `<i>` tags for automatic styling:
472
+ * - `<b>`: Applies button styling
473
+ * - `<i>`: Applies pill styling
474
+ *
475
+ * @example
476
+ * ```tsx
477
+ * // Using btnStyle prop
478
+ * <Link href="/signup" btnStyle="btn">Sign Up</Link>
479
+ *
480
+ * // Using child wrapper (automatic detection)
481
+ * <Link href="/signup"><b>Sign Up</b></Link>
482
+ * <Link href="/signup"><i>Pill Button</i></Link>
483
+ * ```
484
+ */
485
+ btnStyle?: string;
486
+ /**
487
+ * Event handler called when the link is clicked or activated.
488
+ *
489
+ * **Recommended for most use cases**, especially analytics and tracking.
490
+ * This event fires for:
491
+ * - Mouse clicks
492
+ * - Touch/tap interactions
493
+ * - Keyboard activation (Enter key)
494
+ * - Assistive technology activation
495
+ *
496
+ * Use `onClick` when you need to track ALL user activations, including
497
+ * keyboard users. This ensures full accessibility coverage.
498
+ *
499
+ * @param event - The mouse event
500
+ * @example
501
+ * ```tsx
502
+ * // ✅ RECOMMENDED: onClick tracks all activation methods
503
+ * <Link
504
+ * href="/products"
505
+ * onClick={(e) => {
506
+ * trackEvent('link_click', { href: '/products' });
507
+ * }}
508
+ * >
509
+ * Products
510
+ * </Link>
511
+ * ```
512
+ */
513
+ onClick?: (event: React.MouseEvent<HTMLAnchorElement>) => void;
514
+ /**
515
+ * Event handler called when a pointer device button is pressed on the link.
516
+ *
517
+ * Use this for specific pointer interactions like:
518
+ * - Drag-and-drop detection
519
+ * - Touch gesture recognition
520
+ * - Distinguishing input types (mouse vs touch vs pen)
521
+ * - Providing early visual feedback before click completes
522
+ *
523
+ * **⚠️ Accessibility Note**: Unlike `onClick`, this does NOT fire for
524
+ * keyboard activation (Enter key). If you need to track all user interactions
525
+ * including keyboard users, use `onClick` instead.
526
+ *
527
+ * @param event - The pointer event
528
+ * @example
529
+ * ```tsx
530
+ * // Use onPointerDown for pointer-specific interactions
531
+ * <Link
532
+ * href="/products"
533
+ * onPointerDown={(e) => {
534
+ * // Distinguish between mouse (2), touch (5), and pen (3)
535
+ * console.log('Pointer type:', e.pointerType);
536
+ * }}
537
+ * >
538
+ * Products
539
+ * </Link>
540
+ * ```
541
+ *
542
+ * @example
543
+ * ```tsx
544
+ * // ✅ Use both handlers together for comprehensive tracking
545
+ * <Link
546
+ * href="/products"
547
+ * onClick={(e) => trackAllActivations(e)}
548
+ * onPointerDown={(e) => provideFeedback(e)}
549
+ * >
550
+ * Products
551
+ * </Link>
552
+ * ```
553
+ */
554
+ onPointerDown?: (event: React.PointerEvent<HTMLAnchorElement>) => void;
555
+ /**
556
+ * Icon element to display in the link (used by IconLink).
557
+ *
558
+ * @example
559
+ * ```tsx
560
+ * <IconLink href="/home" icon={<HomeIcon />} />
561
+ * ```
562
+ */
563
+ icon?: React.ReactNode;
564
+ } & Omit<React.ComponentPropsWithoutRef<"a">, 'style'>;
565
+
331
566
  /**
332
567
  * Props for the TextToSpeechComponent.
333
568
  * @interface TextToSpeechComponentProps
@@ -955,4 +1190,4 @@ type FPComponent = {
955
1190
  */
956
1191
  declare const FP: FPComponent;
957
1192
 
958
- export { Article, Aside, Badge, BadgeProps, FP as Box, Caption, ComponentProps$1 as ComponentProps, Details, FP, Footer, Header, Img, ImgProps, Landmarks, Main, Section, Table, Tag, TagProps, TagVariant, Tbody, Td, TextToSpeech, Thead, Tr };
1193
+ export { Article, Aside, Badge, BadgeProps, FP as Box, Caption, ComponentProps$1 as ComponentProps, Details, FP, Footer, Header, Img, ImgProps, Landmarks, LinkProps, Main, Section, Table, Tag, TagProps, TagVariant, Tbody, Td, TextToSpeech, Thead, Tr };
package/libs/index.js CHANGED
@@ -2,24 +2,24 @@ import { b } from './chunk-IRLFZ3OL.js';
2
2
  export { a as Textarea } from './chunk-IRLFZ3OL.js';
3
3
  export { a as Field } from './chunk-HRRHPLER.js';
4
4
  export { a as Caption, i as TBL, f as Table, c as Tbody, e as Td, b as Thead, d as Tr } from './chunk-Y2PFDELK.js';
5
- export { a as Dialog } from './chunk-X3JCTEPD.js';
5
+ export { a as Dialog } from './chunk-QKHPHMG2.js';
6
6
  export { c as Nav, b as NavItem, a as NavList } from './chunk-FVROL3V5.js';
7
7
  export { b as List } from './chunk-IEB64SWY.js';
8
8
  export { b as Popover } from './chunk-23ANBDCR.js';
9
9
  export { a as Text } from './chunk-IQ76HGVP.js';
10
10
  export { b as Heading, a as Title } from './chunk-ZFJ4U45S.js';
11
- export { b as Breadcrumb, a as useBreadcrumbSegments } from './chunk-X5LGFCWG.js';
11
+ export { b as Breadcrumb, a as useBreadcrumbSegments } from './chunk-UJAQVHWC.js';
12
12
  import './chunk-GCGKYLDG.js';
13
13
  import { b as b$1 } from './chunk-5QD3DWFI.js';
14
14
  export { a as Icon } from './chunk-5QD3DWFI.js';
15
15
  export { d as Card, b as CardContent, c as CardFooter, a as CardTitle } from './chunk-KK47SYZI.js';
16
- export { a as Modal } from './chunk-7XPFW7CB.js';
17
- export { a as Button } from './chunk-OVWLQYMK.js';
16
+ export { a as Modal } from './chunk-43TK2ICH.js';
17
+ export { a as Button } from './chunk-KVKQLRJG.js';
18
18
  export { a as Input } from './chunk-F5EYMVQM.js';
19
19
  export { a as Box, a as FP } from './chunk-6SAHIYCZ.js';
20
20
  import './chunk-BFK62VX5.js';
21
21
  import './chunk-75QHTLFO.js';
22
- export { a as Link, b as To } from './chunk-UEPAWMDF.js';
22
+ export { a as Link, d as To } from './chunk-NNTBIHSD.js';
23
23
  import { a } from './chunk-HHLNOC5T.js';
24
24
  import u, { useCallback, useMemo, useState, useEffect } from 'react';
25
25
 
package/package.json CHANGED
@@ -2,7 +2,7 @@
2
2
  "name": "@fpkit/acss",
3
3
  "description": "A lightweight React UI library for building modern and accessible components that leverage CSS custom properties for reactive Styles.",
4
4
  "private": false,
5
- "version": "1.0.0-beta.1",
5
+ "version": "2.0.0",
6
6
  "engines": {
7
7
  "node": ">=22.12.0",
8
8
  "npm": ">=8.0.0"
@@ -102,7 +102,8 @@
102
102
  "files": [
103
103
  "src",
104
104
  "libs",
105
- "libs/index.css"
105
+ "libs/index.css",
106
+ "docs"
106
107
  ],
107
108
  "peerDependencies": {
108
109
  "react": "^18.0.0",
@@ -125,5 +126,5 @@
125
126
  "publishConfig": {
126
127
  "access": "public"
127
128
  },
128
- "gitHead": "9c4bba23e1f85ae1ec81a63ec9488a5e36ff5c5b"
129
+ "gitHead": "c26374b7d65656bf57e002cbf44dab95ce8f0197"
129
130
  }
@@ -1,6 +1,6 @@
1
1
  import { Meta } from "@storybook/addon-docs/blocks";
2
2
 
3
- <Meta title="ACSS UI" />
3
+ <Meta title="FP/ACSS UI" />
4
4
 
5
5
  # UI Component
6
6
 
@@ -342,12 +342,11 @@ describe("Breadcrumb", () => {
342
342
  currentRoute="/products/shirts"
343
343
  linkProps={{
344
344
  onClick: handleClick,
345
- "data-testid": "breadcrumb-link",
346
345
  }}
347
346
  />
348
347
  );
349
348
 
350
- const links = screen.getAllByTestId("breadcrumb-link");
349
+ const links = screen.getAllByRole("link");
351
350
  expect(links.length).toBeGreaterThan(0);
352
351
 
353
352
  // Click first link
@@ -93,30 +93,38 @@ export default AdvancedButton;
93
93
 
94
94
  ### Overview
95
95
 
96
- The Button component now uses an **optimized disabled state implementation** that follows WCAG 2.1 Level AA accessibility guidelines. This update brings significant performance improvements and better accessibility compliance.
96
+ The Button component now uses an **optimized disabled state implementation**
97
+ that follows WCAG 2.1 Level AA accessibility guidelines. This update brings
98
+ significant performance improvements and better accessibility compliance.
97
99
 
98
100
  ### Key Improvements
99
101
 
100
102
  #### 1. **ARIA-Disabled Pattern**
101
103
 
102
- Instead of using the native `disabled` attribute, the button uses `aria-disabled`:
104
+ Instead of using the native `disabled` attribute, the button uses
105
+ `aria-disabled`:
103
106
 
104
- - **Stays in tab order** - Screen reader users can discover and navigate to disabled buttons
105
- - **Allows focus** - Users can still focus disabled buttons to read tooltips or help text
106
- - **Prevents interactions** - All click/keyboard events are blocked when disabled
107
+ - **Stays in tab order** - Screen reader users can discover and navigate to
108
+ disabled buttons
109
+ - **Allows focus** - Users can still focus disabled buttons to read tooltips or
110
+ help text
111
+ - **Prevents interactions** - All click/keyboard events are blocked when
112
+ disabled
107
113
  - **Better styling control** - Meets WCAG AA contrast requirements more easily
108
114
 
109
115
  #### 2. **Performance Optimizations**
110
116
 
111
117
  The new `useDisabledState` hook provides:
112
118
 
113
- - **~90% reduction in unnecessary re-renders** compared to previous implementation
119
+ - **~90% reduction in unnecessary re-renders** compared to previous
120
+ implementation
114
121
  - **Stable handler references** - Event handlers don't recreate on every render
115
122
  - **Optimized memoization** - Single memoization pass for all props and handlers
116
123
 
117
124
  #### 3. **Automatic className Merging**
118
125
 
119
- The disabled state now automatically merges your custom classes with the `.is-disabled` class:
126
+ The disabled state now automatically merges your custom classes with the
127
+ `.is-disabled` class:
120
128
 
121
129
  ```tsx
122
130
  // Before: You had to manage className manually
@@ -188,10 +196,12 @@ This implementation follows:
188
196
  ### Related
189
197
 
190
198
  - See [useDisabledState Hook](/docs/hooks/use-disabled-state) for advanced usage
191
- - See [Accessibility Guide](/docs/guides/accessibility) for WCAG compliance details
199
+ - See [Accessibility Guide](/docs/guides/accessibility) for WCAG compliance
200
+ details
192
201
 
193
202
  ## Additional Notes
194
203
 
195
204
  - Ensure the `type` prop is set to one of `'button'`, `'submit'`, or `'reset'`.
196
205
  - The `styles` prop can be used to apply inline styles to the button.
197
- - The `disabled` prop uses the accessible `aria-disabled` pattern instead of native `disabled` attribute.
206
+ - The `disabled` prop uses the accessible `aria-disabled` pattern instead of
207
+ native `disabled` attribute.
@@ -74,6 +74,11 @@ button {
74
74
  }
75
75
  }
76
76
 
77
+ &:focus-visible {
78
+ outline: var(--btn-focus-outline, 2px solid currentColor);
79
+ outline-offset: var(--btn-focus-outline-offset, 1px);
80
+ }
81
+
77
82
  &[type="reset"] {
78
83
  --btn-bg: transparent;
79
84
  --btn-color: gray;