@allxsmith/bestax-bulma 5.16.7 → 5.16.9

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/index.esm.js CHANGED
@@ -1279,6 +1279,22 @@ const avatarSizes = [
1279
1279
  '96x96',
1280
1280
  '128x128',
1281
1281
  ];
1282
+ /**
1283
+ * The roles a caller can use to say "this avatar is not a control", and so claim
1284
+ * the non-interactive treatment for a custom `as` target we would otherwise have
1285
+ * to guess about.
1286
+ *
1287
+ * Read by VALUE, not by presence. Any role at all used to count, which let
1288
+ * `role="button"` — a claim of the opposite — route a real control into the
1289
+ * decorative branch and come out `aria-hidden` and nameless. `img` is what the
1290
+ * fallback itself applies; `presentation` and `none` are the standard ways to say
1291
+ * an element carries no semantics, which is what pairs with `alt=""`.
1292
+ */
1293
+ const NON_INTERACTIVE_ROLES = [
1294
+ 'img',
1295
+ 'presentation',
1296
+ 'none',
1297
+ ];
1282
1298
  /**
1283
1299
  * Derives a small set of initials from a name (e.g. "Ada Lovelace" -> "AL").
1284
1300
  */
@@ -1373,17 +1389,63 @@ const Avatar = forwardRef(function Avatar(avatarProps, ref) {
1373
1389
  const combinedClasses = classNames(avatarClasses, bulmaHelperClasses, className);
1374
1390
  const initialsClass = usePrefixedClassNames('avatar-initials');
1375
1391
  const Tag = as ?? (href ? 'a' : 'figure');
1376
- // A custom `as` component given an href is being used as a link — the same
1377
- // condition under which isLinkLike forwards href/target/rel below — so it
1378
- // counts as interactive too. Otherwise alt="" would mark a real link
1379
- // decorative (aria-hidden) and it could render nameless.
1392
+ // A custom component counts as interactive whether or not it was given OUR
1393
+ // href: a router link takes `to`, creates the anchor itself, and cannot be
1394
+ // classified from the props it arrives with (#668). Marking a real link as a
1395
+ // picture is the worse failure — and `alt=""` would go further and mark it
1396
+ // decorative (aria-hidden), leaving it nameless.
1397
+ //
1398
+ // A custom ELEMENT still needs the href. A hyphenated tag renders a real DOM
1399
+ // element of that name, so nothing is hidden from us: without a link to follow
1400
+ // it is still a picture. `Navbar.Link` draws the same line for `role="button"`.
1401
+ //
1402
+ // Where we are guessing, the caller settles it: an explicit `role` or
1403
+ // `aria-hidden` states the semantics, so a custom component that really is a
1404
+ // wrapper gets `role="img"` and its `alt=""` opt-out back. `role` alone would
1405
+ // be a half-override — interactivity also drives the decorative opt-out and the
1406
+ // name fallback, and overriding one of the three is worse than overriding none.
1407
+ //
1408
+ // An `href` ENDS the guess, so it outranks the signal. `as="a"`, `as="button"`
1409
+ // and a target we were handed an href for are known to be interactive, and there
1410
+ // the rule that an interactive element always carries an accessible name is not
1411
+ // the caller's to waive: without this, `as={RouterLink} href="/x" role="img"`
1412
+ // with `alt=""` rendered a real anchor as `aria-hidden` and nameless — the very
1413
+ // failure #668 is about. `Navbar.Link` orders the same two the same way.
1414
+ //
1415
+ // The signal has to MEAN what it is used for, so both halves read a value rather
1416
+ // than a presence — the way `Navbar.Link` reads `role === 'button'`. A role only
1417
+ // claims to be a picture if it says so: `role="button"` or `role="link"` is the
1418
+ // opposite claim, and taking any role as the signal handed an interactive-role
1419
+ // element `aria-hidden` and no name. Likewise `aria-hidden={false}` denies
1420
+ // hiding, so only a truthy one counts.
1421
+ const ariaHidden = rest['aria-hidden'];
1422
+ const statesItIsNotAControl = (rest.role !== undefined && NON_INTERACTIVE_ROLES.includes(rest.role)) ||
1423
+ ariaHidden === true ||
1424
+ ariaHidden === 'true';
1425
+ const customTargetStatesSemantics = typeof Tag !== 'string' && href == null && statesItIsNotAControl;
1380
1426
  const isInteractive = Tag === 'a' ||
1381
1427
  Tag === 'button' ||
1382
- ((typeof Tag !== 'string' || isCustomElement(Tag)) && href != null);
1428
+ (typeof Tag !== 'string' && !customTargetStatesSemantics) ||
1429
+ (isCustomElement(Tag) && href != null);
1383
1430
  // Only forward link attributes when rendering an anchor or a custom (non-DOM)
1384
1431
  // component; a plain `as="div"` must not receive a stray `href`/`target`/`rel`.
1385
1432
  const isLinkLike = Tag === 'a' || typeof Tag !== 'string' || isCustomElement(Tag);
1386
- const linkProps = isLinkLike ? { href, target, rel } : {};
1433
+ // Present-only, not `{ href, target, rel }`. An unconditional spread hands the
1434
+ // target these keys whatever the caller passed, and a key existing is not free:
1435
+ // a target that tests for one sees a link where there is none, and one that
1436
+ // spreads its own `{...rest}` onward passes the nothing along. It is NOT about
1437
+ // a destructuring default, which an explicit `undefined` triggers just as an
1438
+ // absent key does. What stops a target that REQUIRES one from being rendered
1439
+ // without it is the type (#665) — this is the smaller half, and the backstop for
1440
+ // the callers a type does not reach: a plain-JavaScript one and a loose spread,
1441
+ // the same pair `Button` and `Menu.Item` keep their own filters for.
1442
+ const linkProps = isLinkLike
1443
+ ? {
1444
+ ...(href !== undefined && { href }),
1445
+ ...(target !== undefined && { target }),
1446
+ ...(rel !== undefined && { rel }),
1447
+ }
1448
+ : {};
1387
1449
  // alt coalesces with ?? (not ||) so an explicit alt="" survives as the
1388
1450
  // standard decorative marker instead of being overridden by name.
1389
1451
  const accessibleName = alt ?? name;
@@ -2884,7 +2946,27 @@ const NavbarLink = forwardRef(function NavbarLink(linkProps, ref) {
2884
2946
  });
2885
2947
  const dropdownContext = useContext(NavbarDropdownContext);
2886
2948
  const hasHref = rest.href !== undefined;
2887
- const isNativeInteractive = Component === 'button' || hasHref;
2949
+ // What a custom component renders cannot be read off its input props, and the
2950
+ // prop that ends in an anchor belongs to the router, not to us — `to`, `state`,
2951
+ // `params` and a dozen further spellings all get there. Sniffing for more names
2952
+ // trades one wrong guess for another, so a non-string `as` counts as
2953
+ // interactive: announcing a real anchor as a button, and layering a synthetic
2954
+ // click over its navigation, is the worse of the two failures (#668).
2955
+ //
2956
+ // A custom ELEMENT stays out of it. A hyphenated tag is a real DOM element and
2957
+ // none of those is natively interactive, so `<x-trigger>` keeps the fallback
2958
+ // exactly like `as="span"` — the same line `Avatar` draws for `role="img"`.
2959
+ //
2960
+ // Where we are guessing, the caller settles it: a custom target that declares
2961
+ // `role="button"` is saying it is a button and not a link, so it takes the
2962
+ // whole fallback — including the click, which is the half it could not supply
2963
+ // itself. `Avatar` gives the same escape hatch to the same guess. An `href`
2964
+ // still wins: a target with somewhere to navigate is a link whatever role it
2965
+ // claims.
2966
+ const customTargetIsButton = typeof Component !== 'string' && rest.role === 'button';
2967
+ const isNativeInteractive = Component === 'button' ||
2968
+ (typeof Component !== 'string' && !customTargetIsButton) ||
2969
+ hasHref;
2888
2970
  // Guarded like Button's disabled blocker: these run on whatever `as` renders,
2889
2971
  // and a custom target's callback need not take a DOM event. One declaring
2890
2972
  // `onKeyDown: (k: {key: string}) => void` reaches `e.preventDefault()` and