only-child.mjs 2.1 KB

1234567891011121314151617181920212223242526272829303132333435363738394041424344454647484950515253545556575859606162636465
  1. import { defineComponent, inject, withDirectives, cloneVNode, Comment, Fragment, Text, createVNode } from 'vue';
  2. import { FORWARD_REF_INJECTION_KEY, useForwardRefDirective } from '../../../hooks/use-forward-ref/index.mjs';
  3. import { NOOP, isObject } from '@vue/shared';
  4. import { debugWarn } from '../../../utils/error.mjs';
  5. import { useNamespace } from '../../../hooks/use-namespace/index.mjs';
  6. const NAME = "ElOnlyChild";
  7. const OnlyChild = defineComponent({
  8. name: NAME,
  9. setup(_, {
  10. slots,
  11. attrs
  12. }) {
  13. var _a;
  14. const forwardRefInjection = inject(FORWARD_REF_INJECTION_KEY);
  15. const forwardRefDirective = useForwardRefDirective((_a = forwardRefInjection == null ? void 0 : forwardRefInjection.setForwardRef) != null ? _a : NOOP);
  16. return () => {
  17. var _a2;
  18. const defaultSlot = (_a2 = slots.default) == null ? void 0 : _a2.call(slots, attrs);
  19. if (!defaultSlot)
  20. return null;
  21. const [firstLegitNode, length] = findFirstLegitChild(defaultSlot);
  22. if (!firstLegitNode) {
  23. debugWarn(NAME, "no valid child node found");
  24. return null;
  25. }
  26. if (length > 1) {
  27. debugWarn(NAME, "requires exact only one valid child.");
  28. }
  29. return withDirectives(cloneVNode(firstLegitNode, attrs), [[forwardRefDirective]]);
  30. };
  31. }
  32. });
  33. function findFirstLegitChild(node) {
  34. if (!node)
  35. return [null, 0];
  36. const children = node;
  37. const len = children.filter((c) => c.type !== Comment).length;
  38. for (const child of children) {
  39. if (isObject(child)) {
  40. switch (child.type) {
  41. case Comment:
  42. continue;
  43. case Text:
  44. case "svg":
  45. return [wrapTextContent(child), len];
  46. case Fragment:
  47. return findFirstLegitChild(child.children);
  48. default:
  49. return [child, len];
  50. }
  51. }
  52. return [wrapTextContent(child), len];
  53. }
  54. return [null, 0];
  55. }
  56. function wrapTextContent(s) {
  57. const ns = useNamespace("only-child");
  58. return createVNode("span", {
  59. "class": ns.e("content")
  60. }, [s]);
  61. }
  62. export { OnlyChild };
  63. //# sourceMappingURL=only-child.mjs.map