love-ui 1.2.12 → 1.2.14
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.js +8 -7
- package/dist/mcp-server.js +1 -1
- package/package.json +3 -2
- package/packages/loveui-skills/SKILL.md +99 -0
- package/packages/loveui-skills/agents/openai.yaml +11 -0
- package/packages/loveui-skills/references/design-directions.md +60 -0
- package/packages/loveui-skills/references/mcp-catalog-workflow.md +68 -0
- package/packages/loveui-skills/references/page-blueprints.md +76 -0
- package/packages/loveui-skills/references/quality-gates.md +51 -0
- package/public/r/accordion-controlled.json +1 -1
- package/public/r/accordion-demo.json +1 -1
- package/public/r/accordion-multiple.json +1 -1
- package/public/r/accordion-single.json +1 -1
- package/public/r/alert-demo.json +1 -1
- package/public/r/alert-dialog-demo.json +1 -1
- package/public/r/alert-error.json +1 -1
- package/public/r/alert-info.json +1 -1
- package/public/r/alert-success.json +1 -1
- package/public/r/alert-warning.json +1 -1
- package/public/r/alert-with-icon-action.json +1 -1
- package/public/r/alert-with-icon.json +1 -1
- package/public/r/announcement-tagless.json +1 -1
- package/public/r/announcement-themes.json +1 -1
- package/public/r/announcement.json +1 -1
- package/public/r/autocomplete-async.json +1 -1
- package/public/r/autocomplete-autohighlight.json +1 -1
- package/public/r/autocomplete-demo.json +1 -1
- package/public/r/autocomplete-disabled.json +1 -1
- package/public/r/autocomplete-form.json +1 -1
- package/public/r/autocomplete-grouped.json +1 -1
- package/public/r/autocomplete-inline.json +1 -1
- package/public/r/autocomplete-lg.json +1 -1
- package/public/r/autocomplete-limit.json +1 -1
- package/public/r/autocomplete-sm.json +1 -1
- package/public/r/autocomplete-with-clear.json +1 -1
- package/public/r/autocomplete-with-label.json +1 -1
- package/public/r/autocomplete-with-trigger-clear.json +1 -1
- package/public/r/avatar-demo.json +1 -1
- package/public/r/avatar-fallback.json +1 -1
- package/public/r/avatar-group.json +1 -1
- package/public/r/avatar-radius.json +1 -1
- package/public/r/avatar-size.json +1 -1
- package/public/r/avatar-stack-hover.json +1 -1
- package/public/r/avatar-stack.json +1 -1
- package/public/r/badge-demo.json +1 -1
- package/public/r/badge-destructive.json +1 -1
- package/public/r/badge-error.json +1 -1
- package/public/r/badge-info.json +1 -1
- package/public/r/badge-lg.json +1 -1
- package/public/r/badge-outline.json +1 -1
- package/public/r/badge-secondary.json +1 -1
- package/public/r/badge-sm.json +1 -1
- package/public/r/badge-success.json +1 -1
- package/public/r/badge-warning.json +1 -1
- package/public/r/badge-with-icon.json +1 -1
- package/public/r/badge-with-link.json +1 -1
- package/public/r/banner-inset.json +1 -1
- package/public/r/banner-themes.json +1 -1
- package/public/r/banner.json +1 -1
- package/public/r/bookmarks.json +206 -0
- package/public/r/breadcrumb-custom-separator.json +1 -1
- package/public/r/breadcrumb-demo.json +1 -1
- package/public/r/button-demo.json +1 -1
- package/public/r/button-destructive-outline.json +1 -1
- package/public/r/button-destructive.json +1 -1
- package/public/r/button-disabled.json +1 -1
- package/public/r/button-ghost.json +1 -1
- package/public/r/button-lg.json +1 -1
- package/public/r/button-link.json +1 -1
- package/public/r/button-loading.json +1 -1
- package/public/r/button-outline.json +1 -1
- package/public/r/button-secondary.json +1 -1
- package/public/r/button-sm.json +1 -1
- package/public/r/button-with-icon.json +1 -1
- package/public/r/button-with-link.json +1 -1
- package/public/r/button-xl.json +1 -1
- package/public/r/button-xs.json +1 -1
- package/public/r/calendar-headless.json +1 -1
- package/public/r/calendar-rac.json +16 -0
- package/public/r/calendar.json +1 -1
- package/public/r/card-demo.json +1 -1
- package/public/r/chart.json +15 -0
- package/public/r/checkbox-card.json +1 -1
- package/public/r/checkbox-demo.json +1 -1
- package/public/r/checkbox-disabled.json +1 -1
- package/public/r/checkbox-form.json +1 -1
- package/public/r/checkbox-group-demo.json +1 -1
- package/public/r/checkbox-group-disabled.json +1 -1
- package/public/r/checkbox-group-form.json +1 -1
- package/public/r/checkbox-group-nested-parent.json +1 -1
- package/public/r/checkbox-group-parent.json +1 -1
- package/public/r/checkbox-tree.json +12 -0
- package/public/r/checkbox-with-description.json +1 -1
- package/public/r/choicebox-inline.json +1 -1
- package/public/r/choicebox.json +1 -1
- package/public/r/codebase.json +1 -1
- package/public/r/collaborative-canvas.json +1 -1
- package/public/r/collapsible-demo.json +1 -1
- package/public/r/combobox-autohighlight.json +1 -1
- package/public/r/combobox-controlled.json +1 -1
- package/public/r/combobox-create-new.json +1 -1
- package/public/r/combobox-demo.json +1 -1
- package/public/r/combobox-disabled.json +1 -1
- package/public/r/combobox-fixed-width.json +1 -1
- package/public/r/combobox-form.json +1 -1
- package/public/r/combobox-grouped.json +1 -1
- package/public/r/combobox-lg.json +1 -1
- package/public/r/combobox-multiple-form.json +1 -1
- package/public/r/combobox-multiple.json +1 -1
- package/public/r/combobox-sm.json +1 -1
- package/public/r/combobox-with-clear.json +1 -1
- package/public/r/combobox-with-inner-input.json +1 -1
- package/public/r/combobox-with-label.json +1 -1
- package/public/r/command.json +18 -0
- package/public/r/comp-01.json +22 -0
- package/public/r/comp-02.json +23 -0
- package/public/r/comp-03.json +23 -0
- package/public/r/comp-04.json +23 -0
- package/public/r/comp-05.json +22 -0
- package/public/r/comp-06.json +23 -0
- package/public/r/comp-07.json +22 -0
- package/public/r/comp-08.json +23 -0
- package/public/r/comp-09.json +22 -0
- package/public/r/comp-10.json +22 -0
- package/public/r/comp-100.json +23 -0
- package/public/r/comp-101.json +23 -0
- package/public/r/comp-102.json +23 -0
- package/public/r/comp-103.json +23 -0
- package/public/r/comp-104.json +23 -0
- package/public/r/comp-105.json +23 -0
- package/public/r/comp-106.json +22 -0
- package/public/r/comp-107.json +22 -0
- package/public/r/comp-108.json +23 -0
- package/public/r/comp-109.json +22 -0
- package/public/r/comp-11.json +22 -0
- package/public/r/comp-110.json +22 -0
- package/public/r/comp-111.json +21 -0
- package/public/r/comp-112.json +21 -0
- package/public/r/comp-113.json +22 -0
- package/public/r/comp-114.json +23 -0
- package/public/r/comp-115.json +22 -0
- package/public/r/comp-116.json +22 -0
- package/public/r/comp-117.json +23 -0
- package/public/r/comp-118.json +23 -0
- package/public/r/comp-119.json +27 -0
- package/public/r/comp-12.json +22 -0
- package/public/r/comp-120.json +27 -0
- package/public/r/comp-121.json +27 -0
- package/public/r/comp-122.json +27 -0
- package/public/r/comp-123.json +22 -0
- package/public/r/comp-124.json +22 -0
- package/public/r/comp-125.json +31 -0
- package/public/r/comp-126.json +31 -0
- package/public/r/comp-127.json +21 -0
- package/public/r/comp-128.json +21 -0
- package/public/r/comp-129.json +24 -0
- package/public/r/comp-13.json +22 -0
- package/public/r/comp-130.json +23 -0
- package/public/r/comp-131.json +23 -0
- package/public/r/comp-132.json +23 -0
- package/public/r/comp-133.json +23 -0
- package/public/r/comp-134.json +23 -0
- package/public/r/comp-135.json +24 -0
- package/public/r/comp-136.json +23 -0
- package/public/r/comp-137.json +23 -0
- package/public/r/comp-138.json +25 -0
- package/public/r/comp-139.json +23 -0
- package/public/r/comp-14.json +22 -0
- package/public/r/comp-140.json +23 -0
- package/public/r/comp-141.json +23 -0
- package/public/r/comp-142.json +25 -0
- package/public/r/comp-143.json +23 -0
- package/public/r/comp-144.json +24 -0
- package/public/r/comp-145.json +24 -0
- package/public/r/comp-146.json +24 -0
- package/public/r/comp-147.json +24 -0
- package/public/r/comp-148.json +25 -0
- package/public/r/comp-149.json +24 -0
- package/public/r/comp-15.json +22 -0
- package/public/r/comp-150.json +21 -0
- package/public/r/comp-151.json +23 -0
- package/public/r/comp-152.json +23 -0
- package/public/r/comp-153.json +23 -0
- package/public/r/comp-154.json +23 -0
- package/public/r/comp-155.json +23 -0
- package/public/r/comp-156.json +25 -0
- package/public/r/comp-157.json +27 -0
- package/public/r/comp-158.json +24 -0
- package/public/r/comp-159.json +24 -0
- package/public/r/comp-16.json +22 -0
- package/public/r/comp-160.json +24 -0
- package/public/r/comp-161.json +24 -0
- package/public/r/comp-162.json +24 -0
- package/public/r/comp-163.json +28 -0
- package/public/r/comp-164.json +24 -0
- package/public/r/comp-165.json +24 -0
- package/public/r/comp-166.json +25 -0
- package/public/r/comp-167.json +24 -0
- package/public/r/comp-168.json +24 -0
- package/public/r/comp-169.json +23 -0
- package/public/r/comp-17.json +25 -0
- package/public/r/comp-170.json +25 -0
- package/public/r/comp-171.json +28 -0
- package/public/r/comp-172.json +23 -0
- package/public/r/comp-173.json +23 -0
- package/public/r/comp-174.json +23 -0
- package/public/r/comp-175.json +23 -0
- package/public/r/comp-176.json +23 -0
- package/public/r/comp-177.json +23 -0
- package/public/r/comp-178.json +23 -0
- package/public/r/comp-179.json +24 -0
- package/public/r/comp-18.json +25 -0
- package/public/r/comp-180.json +23 -0
- package/public/r/comp-181.json +25 -0
- package/public/r/comp-182.json +24 -0
- package/public/r/comp-183.json +25 -0
- package/public/r/comp-184.json +25 -0
- package/public/r/comp-185.json +24 -0
- package/public/r/comp-186.json +25 -0
- package/public/r/comp-187.json +25 -0
- package/public/r/comp-188.json +25 -0
- package/public/r/comp-189.json +23 -0
- package/public/r/comp-19.json +23 -0
- package/public/r/comp-190.json +23 -0
- package/public/r/comp-191.json +24 -0
- package/public/r/comp-192.json +23 -0
- package/public/r/comp-193.json +23 -0
- package/public/r/comp-194.json +24 -0
- package/public/r/comp-195.json +23 -0
- package/public/r/comp-196.json +24 -0
- package/public/r/comp-197.json +23 -0
- package/public/r/comp-198.json +23 -0
- package/public/r/comp-199.json +23 -0
- package/public/r/comp-20.json +23 -0
- package/public/r/comp-200.json +25 -0
- package/public/r/comp-201.json +22 -0
- package/public/r/comp-202.json +22 -0
- package/public/r/comp-203.json +23 -0
- package/public/r/comp-204.json +23 -0
- package/public/r/comp-205.json +23 -0
- package/public/r/comp-206.json +24 -0
- package/public/r/comp-207.json +23 -0
- package/public/r/comp-208.json +23 -0
- package/public/r/comp-209.json +23 -0
- package/public/r/comp-21.json +23 -0
- package/public/r/comp-210.json +24 -0
- package/public/r/comp-211.json +24 -0
- package/public/r/comp-212.json +23 -0
- package/public/r/comp-213.json +23 -0
- package/public/r/comp-214.json +23 -0
- package/public/r/comp-215.json +24 -0
- package/public/r/comp-216.json +22 -0
- package/public/r/comp-217.json +22 -0
- package/public/r/comp-218.json +25 -0
- package/public/r/comp-219.json +23 -0
- package/public/r/comp-22.json +23 -0
- package/public/r/comp-220.json +24 -0
- package/public/r/comp-221.json +23 -0
- package/public/r/comp-222.json +26 -0
- package/public/r/comp-223.json +26 -0
- package/public/r/comp-224.json +23 -0
- package/public/r/comp-225.json +24 -0
- package/public/r/comp-226.json +26 -0
- package/public/r/comp-227.json +26 -0
- package/public/r/comp-228.json +26 -0
- package/public/r/comp-229.json +30 -0
- package/public/r/comp-23.json +24 -0
- package/public/r/comp-230.json +30 -0
- package/public/r/comp-231.json +32 -0
- package/public/r/comp-232.json +31 -0
- package/public/r/comp-233.json +30 -0
- package/public/r/comp-234.json +28 -0
- package/public/r/comp-235.json +28 -0
- package/public/r/comp-236.json +24 -0
- package/public/r/comp-237.json +26 -0
- package/public/r/comp-238.json +26 -0
- package/public/r/comp-239.json +26 -0
- package/public/r/comp-24.json +23 -0
- package/public/r/comp-240.json +23 -0
- package/public/r/comp-241.json +24 -0
- package/public/r/comp-242.json +23 -0
- package/public/r/comp-243.json +23 -0
- package/public/r/comp-244.json +23 -0
- package/public/r/comp-245.json +23 -0
- package/public/r/comp-246.json +23 -0
- package/public/r/comp-247.json +23 -0
- package/public/r/comp-248.json +23 -0
- package/public/r/comp-249.json +24 -0
- package/public/r/comp-25.json +24 -0
- package/public/r/comp-250.json +25 -0
- package/public/r/comp-251.json +25 -0
- package/public/r/comp-252.json +25 -0
- package/public/r/comp-253.json +25 -0
- package/public/r/comp-254.json +35 -0
- package/public/r/comp-255.json +30 -0
- package/public/r/comp-256.json +25 -0
- package/public/r/comp-257.json +25 -0
- package/public/r/comp-258.json +32 -0
- package/public/r/comp-259.json +26 -0
- package/public/r/comp-26.json +24 -0
- package/public/r/comp-260.json +26 -0
- package/public/r/comp-261.json +24 -0
- package/public/r/comp-262.json +31 -0
- package/public/r/comp-263.json +25 -0
- package/public/r/comp-264.json +33 -0
- package/public/r/comp-265.json +32 -0
- package/public/r/comp-266.json +24 -0
- package/public/r/comp-267.json +19 -0
- package/public/r/comp-268.json +19 -0
- package/public/r/comp-269.json +19 -0
- package/public/r/comp-27.json +24 -0
- package/public/r/comp-270.json +19 -0
- package/public/r/comp-271.json +19 -0
- package/public/r/comp-272.json +19 -0
- package/public/r/comp-273.json +19 -0
- package/public/r/comp-274.json +19 -0
- package/public/r/comp-275.json +19 -0
- package/public/r/comp-276.json +19 -0
- package/public/r/comp-277.json +21 -0
- package/public/r/comp-278.json +21 -0
- package/public/r/comp-279.json +23 -0
- package/public/r/comp-28.json +24 -0
- package/public/r/comp-280.json +23 -0
- package/public/r/comp-281.json +23 -0
- package/public/r/comp-282.json +23 -0
- package/public/r/comp-283.json +23 -0
- package/public/r/comp-284.json +23 -0
- package/public/r/comp-285.json +23 -0
- package/public/r/comp-286.json +23 -0
- package/public/r/comp-287.json +24 -0
- package/public/r/comp-288.json +23 -0
- package/public/r/comp-289.json +24 -0
- package/public/r/comp-29.json +24 -0
- package/public/r/comp-290.json +24 -0
- package/public/r/comp-291.json +24 -0
- package/public/r/comp-292.json +24 -0
- package/public/r/comp-293.json +26 -0
- package/public/r/comp-294.json +24 -0
- package/public/r/comp-295.json +23 -0
- package/public/r/comp-296.json +23 -0
- package/public/r/comp-297.json +30 -0
- package/public/r/comp-298.json +26 -0
- package/public/r/comp-299.json +28 -0
- package/public/r/comp-30.json +23 -0
- package/public/r/comp-300.json +29 -0
- package/public/r/comp-301.json +24 -0
- package/public/r/comp-302.json +18 -0
- package/public/r/comp-303.json +18 -0
- package/public/r/comp-304.json +18 -0
- package/public/r/comp-305.json +21 -0
- package/public/r/comp-306.json +21 -0
- package/public/r/comp-307.json +21 -0
- package/public/r/comp-308.json +21 -0
- package/public/r/comp-309.json +21 -0
- package/public/r/comp-31.json +21 -0
- package/public/r/comp-310.json +23 -0
- package/public/r/comp-311.json +20 -0
- package/public/r/comp-312.json +21 -0
- package/public/r/comp-313.json +26 -0
- package/public/r/comp-314.json +26 -0
- package/public/r/comp-315.json +24 -0
- package/public/r/comp-316.json +25 -0
- package/public/r/comp-317.json +24 -0
- package/public/r/comp-318.json +24 -0
- package/public/r/comp-319.json +24 -0
- package/public/r/comp-32.json +21 -0
- package/public/r/comp-320.json +27 -0
- package/public/r/comp-321.json +28 -0
- package/public/r/comp-322.json +27 -0
- package/public/r/comp-323.json +30 -0
- package/public/r/comp-324.json +28 -0
- package/public/r/comp-325.json +29 -0
- package/public/r/comp-326.json +30 -0
- package/public/r/comp-327.json +30 -0
- package/public/r/comp-328.json +37 -0
- package/public/r/comp-329.json +38 -0
- package/public/r/comp-33.json +18 -0
- package/public/r/comp-330.json +27 -0
- package/public/r/comp-331.json +42 -0
- package/public/r/comp-332.json +25 -0
- package/public/r/comp-333.json +29 -0
- package/public/r/comp-334.json +22 -0
- package/public/r/comp-335.json +22 -0
- package/public/r/comp-336.json +22 -0
- package/public/r/comp-337.json +22 -0
- package/public/r/comp-338.json +22 -0
- package/public/r/comp-339.json +22 -0
- package/public/r/comp-34.json +27 -0
- package/public/r/comp-340.json +22 -0
- package/public/r/comp-341.json +22 -0
- package/public/r/comp-342.json +22 -0
- package/public/r/comp-343.json +22 -0
- package/public/r/comp-344.json +22 -0
- package/public/r/comp-345.json +22 -0
- package/public/r/comp-346.json +22 -0
- package/public/r/comp-347.json +22 -0
- package/public/r/comp-348.json +22 -0
- package/public/r/comp-349.json +22 -0
- package/public/r/comp-35.json +27 -0
- package/public/r/comp-350.json +22 -0
- package/public/r/comp-351.json +22 -0
- package/public/r/comp-352.json +24 -0
- package/public/r/comp-353.json +24 -0
- package/public/r/comp-354.json +23 -0
- package/public/r/comp-355.json +23 -0
- package/public/r/comp-356.json +23 -0
- package/public/r/comp-357.json +23 -0
- package/public/r/comp-358.json +23 -0
- package/public/r/comp-359.json +24 -0
- package/public/r/comp-36.json +26 -0
- package/public/r/comp-360.json +25 -0
- package/public/r/comp-361.json +23 -0
- package/public/r/comp-362.json +24 -0
- package/public/r/comp-363.json +27 -0
- package/public/r/comp-364.json +26 -0
- package/public/r/comp-365.json +24 -0
- package/public/r/comp-366.json +23 -0
- package/public/r/comp-367.json +23 -0
- package/public/r/comp-368.json +23 -0
- package/public/r/comp-369.json +23 -0
- package/public/r/comp-37.json +23 -0
- package/public/r/comp-370.json +23 -0
- package/public/r/comp-371.json +24 -0
- package/public/r/comp-372.json +24 -0
- package/public/r/comp-373.json +25 -0
- package/public/r/comp-374.json +26 -0
- package/public/r/comp-375.json +25 -0
- package/public/r/comp-376.json +26 -0
- package/public/r/comp-377.json +27 -0
- package/public/r/comp-378.json +24 -0
- package/public/r/comp-379.json +24 -0
- package/public/r/comp-38.json +23 -0
- package/public/r/comp-380.json +24 -0
- package/public/r/comp-381.json +26 -0
- package/public/r/comp-382.json +25 -0
- package/public/r/comp-383.json +26 -0
- package/public/r/comp-384.json +24 -0
- package/public/r/comp-385.json +24 -0
- package/public/r/comp-386.json +24 -0
- package/public/r/comp-387.json +28 -0
- package/public/r/comp-388.json +26 -0
- package/public/r/comp-389.json +24 -0
- package/public/r/comp-39.json +23 -0
- package/public/r/comp-390.json +23 -0
- package/public/r/comp-391.json +23 -0
- package/public/r/comp-392.json +23 -0
- package/public/r/comp-393.json +23 -0
- package/public/r/comp-394.json +24 -0
- package/public/r/comp-395.json +24 -0
- package/public/r/comp-396.json +24 -0
- package/public/r/comp-397.json +25 -0
- package/public/r/comp-398.json +26 -0
- package/public/r/comp-399.json +26 -0
- package/public/r/comp-40.json +23 -0
- package/public/r/comp-400.json +20 -0
- package/public/r/comp-401.json +19 -0
- package/public/r/comp-402.json +19 -0
- package/public/r/comp-403.json +19 -0
- package/public/r/comp-404.json +19 -0
- package/public/r/comp-405.json +19 -0
- package/public/r/comp-406.json +19 -0
- package/public/r/comp-407.json +19 -0
- package/public/r/comp-408.json +19 -0
- package/public/r/comp-409.json +22 -0
- package/public/r/comp-41.json +29 -0
- package/public/r/comp-410.json +22 -0
- package/public/r/comp-411.json +22 -0
- package/public/r/comp-412.json +19 -0
- package/public/r/comp-413.json +22 -0
- package/public/r/comp-414.json +22 -0
- package/public/r/comp-415.json +22 -0
- package/public/r/comp-416.json +23 -0
- package/public/r/comp-417.json +22 -0
- package/public/r/comp-418.json +23 -0
- package/public/r/comp-419.json +23 -0
- package/public/r/comp-42.json +30 -0
- package/public/r/comp-420.json +23 -0
- package/public/r/comp-421.json +23 -0
- package/public/r/comp-422.json +23 -0
- package/public/r/comp-423.json +24 -0
- package/public/r/comp-424.json +22 -0
- package/public/r/comp-425.json +23 -0
- package/public/r/comp-426.json +23 -0
- package/public/r/comp-427.json +23 -0
- package/public/r/comp-428.json +23 -0
- package/public/r/comp-429.json +23 -0
- package/public/r/comp-43.json +32 -0
- package/public/r/comp-430.json +23 -0
- package/public/r/comp-431.json +23 -0
- package/public/r/comp-432.json +23 -0
- package/public/r/comp-433.json +24 -0
- package/public/r/comp-434.json +24 -0
- package/public/r/comp-435.json +24 -0
- package/public/r/comp-436.json +24 -0
- package/public/r/comp-437.json +25 -0
- package/public/r/comp-438.json +23 -0
- package/public/r/comp-439.json +24 -0
- package/public/r/comp-44.json +25 -0
- package/public/r/comp-440.json +25 -0
- package/public/r/comp-441.json +25 -0
- package/public/r/comp-442.json +24 -0
- package/public/r/comp-443.json +24 -0
- package/public/r/comp-444.json +24 -0
- package/public/r/comp-445.json +24 -0
- package/public/r/comp-446.json +24 -0
- package/public/r/comp-447.json +25 -0
- package/public/r/comp-448.json +23 -0
- package/public/r/comp-449.json +23 -0
- package/public/r/comp-45.json +25 -0
- package/public/r/comp-450.json +23 -0
- package/public/r/comp-451.json +23 -0
- package/public/r/comp-452.json +23 -0
- package/public/r/comp-453.json +25 -0
- package/public/r/comp-454.json +22 -0
- package/public/r/comp-455.json +22 -0
- package/public/r/comp-456.json +22 -0
- package/public/r/comp-457.json +21 -0
- package/public/r/comp-458.json +22 -0
- package/public/r/comp-459.json +26 -0
- package/public/r/comp-46.json +26 -0
- package/public/r/comp-460.json +26 -0
- package/public/r/comp-461.json +27 -0
- package/public/r/comp-462.json +27 -0
- package/public/r/comp-463.json +30 -0
- package/public/r/comp-464.json +29 -0
- package/public/r/comp-465.json +29 -0
- package/public/r/comp-466.json +21 -0
- package/public/r/comp-467.json +23 -0
- package/public/r/comp-468.json +21 -0
- package/public/r/comp-469.json +21 -0
- package/public/r/comp-47.json +32 -0
- package/public/r/comp-470.json +21 -0
- package/public/r/comp-471.json +21 -0
- package/public/r/comp-472.json +23 -0
- package/public/r/comp-473.json +24 -0
- package/public/r/comp-474.json +22 -0
- package/public/r/comp-475.json +22 -0
- package/public/r/comp-476.json +21 -0
- package/public/r/comp-477.json +31 -0
- package/public/r/comp-478.json +36 -0
- package/public/r/comp-479.json +28 -0
- package/public/r/comp-48.json +32 -0
- package/public/r/comp-480.json +30 -0
- package/public/r/comp-481.json +34 -0
- package/public/r/comp-482.json +33 -0
- package/public/r/comp-483.json +37 -0
- package/public/r/comp-484.json +41 -0
- package/public/r/comp-485.json +43 -0
- package/public/r/comp-486.json +23 -0
- package/public/r/comp-487.json +26 -0
- package/public/r/comp-488.json +27 -0
- package/public/r/comp-489.json +28 -0
- package/public/r/comp-49.json +32 -0
- package/public/r/comp-490.json +23 -0
- package/public/r/comp-491.json +24 -0
- package/public/r/comp-492.json +25 -0
- package/public/r/comp-493.json +23 -0
- package/public/r/comp-494.json +23 -0
- package/public/r/comp-495.json +24 -0
- package/public/r/comp-496.json +23 -0
- package/public/r/comp-497.json +24 -0
- package/public/r/comp-498.json +24 -0
- package/public/r/comp-499.json +24 -0
- package/public/r/comp-50.json +32 -0
- package/public/r/comp-500.json +25 -0
- package/public/r/comp-501.json +25 -0
- package/public/r/comp-502.json +26 -0
- package/public/r/comp-503.json +27 -0
- package/public/r/comp-504.json +28 -0
- package/public/r/comp-505.json +28 -0
- package/public/r/comp-506.json +26 -0
- package/public/r/comp-507.json +27 -0
- package/public/r/comp-508.json +25 -0
- package/public/r/comp-509.json +25 -0
- package/public/r/comp-51.json +23 -0
- package/public/r/comp-510.json +24 -0
- package/public/r/comp-511.json +27 -0
- package/public/r/comp-512.json +27 -0
- package/public/r/comp-513.json +21 -0
- package/public/r/comp-514.json +21 -0
- package/public/r/comp-515.json +21 -0
- package/public/r/comp-516.json +22 -0
- package/public/r/comp-517.json +22 -0
- package/public/r/comp-518.json +21 -0
- package/public/r/comp-519.json +21 -0
- package/public/r/comp-52.json +23 -0
- package/public/r/comp-520.json +22 -0
- package/public/r/comp-521.json +22 -0
- package/public/r/comp-522.json +21 -0
- package/public/r/comp-523.json +21 -0
- package/public/r/comp-524.json +21 -0
- package/public/r/comp-525.json +21 -0
- package/public/r/comp-526.json +22 -0
- package/public/r/comp-527.json +23 -0
- package/public/r/comp-528.json +22 -0
- package/public/r/comp-529.json +22 -0
- package/public/r/comp-53.json +24 -0
- package/public/r/comp-530.json +22 -0
- package/public/r/comp-531.json +22 -0
- package/public/r/comp-532.json +22 -0
- package/public/r/comp-533.json +22 -0
- package/public/r/comp-534.json +22 -0
- package/public/r/comp-535.json +22 -0
- package/public/r/comp-536.json +22 -0
- package/public/r/comp-537.json +22 -0
- package/public/r/comp-538.json +22 -0
- package/public/r/comp-539.json +22 -0
- package/public/r/comp-54.json +26 -0
- package/public/r/comp-540.json +21 -0
- package/public/r/comp-541.json +21 -0
- package/public/r/comp-542.json +124 -0
- package/public/r/comp-543.json +29 -0
- package/public/r/comp-544.json +26 -0
- package/public/r/comp-545.json +29 -0
- package/public/r/comp-546.json +29 -0
- package/public/r/comp-547.json +29 -0
- package/public/r/comp-548.json +29 -0
- package/public/r/comp-549.json +29 -0
- package/public/r/comp-55.json +27 -0
- package/public/r/comp-550.json +29 -0
- package/public/r/comp-551.json +30 -0
- package/public/r/comp-552.json +29 -0
- package/public/r/comp-553.json +29 -0
- package/public/r/comp-554.json +36 -0
- package/public/r/comp-555.json +23 -0
- package/public/r/comp-556.json +23 -0
- package/public/r/comp-557.json +23 -0
- package/public/r/comp-558.json +23 -0
- package/public/r/comp-559.json +23 -0
- package/public/r/comp-56.json +26 -0
- package/public/r/comp-560.json +23 -0
- package/public/r/comp-561.json +25 -0
- package/public/r/comp-562.json +23 -0
- package/public/r/comp-563.json +23 -0
- package/public/r/comp-564.json +24 -0
- package/public/r/comp-565.json +20 -0
- package/public/r/comp-566.json +20 -0
- package/public/r/comp-567.json +20 -0
- package/public/r/comp-568.json +20 -0
- package/public/r/comp-569.json +20 -0
- package/public/r/comp-57.json +26 -0
- package/public/r/comp-570.json +20 -0
- package/public/r/comp-571.json +23 -0
- package/public/r/comp-572.json +23 -0
- package/public/r/comp-573.json +20 -0
- package/public/r/comp-574.json +22 -0
- package/public/r/comp-575.json +20 -0
- package/public/r/comp-576.json +21 -0
- package/public/r/comp-577.json +23 -0
- package/public/r/comp-578.json +28 -0
- package/public/r/comp-579.json +28 -0
- package/public/r/comp-58.json +25 -0
- package/public/r/comp-580.json +29 -0
- package/public/r/comp-581.json +45 -0
- package/public/r/comp-582.json +42 -0
- package/public/r/comp-583.json +41 -0
- package/public/r/comp-584.json +41 -0
- package/public/r/comp-585.json +41 -0
- package/public/r/comp-586.json +34 -0
- package/public/r/comp-587.json +29 -0
- package/public/r/comp-588.json +33 -0
- package/public/r/comp-589.json +37 -0
- package/public/r/comp-59.json +22 -0
- package/public/r/comp-590.json +40 -0
- package/public/r/comp-591.json +29 -0
- package/public/r/comp-592.json +41 -0
- package/public/r/comp-593.json +36 -0
- package/public/r/comp-594.json +33 -0
- package/public/r/comp-595.json +22 -0
- package/public/r/comp-596.json +26 -0
- package/public/r/comp-597.json +22 -0
- package/public/r/comp-598.json +22 -0
- package/public/r/comp-599.json +22 -0
- package/public/r/comp-60.json +23 -0
- package/public/r/comp-600.json +17 -0
- package/public/r/comp-601.json +20 -0
- package/public/r/comp-602.json +17 -0
- package/public/r/comp-603.json +20 -0
- package/public/r/comp-604.json +17 -0
- package/public/r/comp-605.json +17 -0
- package/public/r/comp-606.json +20 -0
- package/public/r/comp-607.json +20 -0
- package/public/r/comp-608.json +20 -0
- package/public/r/comp-609.json +20 -0
- package/public/r/comp-61.json +23 -0
- package/public/r/comp-610.json +23 -0
- package/public/r/comp-611.json +23 -0
- package/public/r/comp-612.json +17 -0
- package/public/r/comp-613.json +20 -0
- package/public/r/comp-614.json +17 -0
- package/public/r/comp-615.json +26 -0
- package/public/r/comp-616.json +26 -0
- package/public/r/comp-617.json +26 -0
- package/public/r/comp-62.json +23 -0
- package/public/r/comp-63.json +22 -0
- package/public/r/comp-64.json +23 -0
- package/public/r/comp-65.json +22 -0
- package/public/r/comp-66.json +22 -0
- package/public/r/comp-67.json +23 -0
- package/public/r/comp-68.json +24 -0
- package/public/r/comp-69.json +24 -0
- package/public/r/comp-70.json +24 -0
- package/public/r/comp-71.json +22 -0
- package/public/r/comp-72.json +21 -0
- package/public/r/comp-73.json +18 -0
- package/public/r/comp-74.json +27 -0
- package/public/r/comp-75.json +22 -0
- package/public/r/comp-76.json +23 -0
- package/public/r/comp-77.json +22 -0
- package/public/r/comp-78.json +21 -0
- package/public/r/comp-79.json +22 -0
- package/public/r/comp-80.json +21 -0
- package/public/r/comp-81.json +21 -0
- package/public/r/comp-82.json +22 -0
- package/public/r/comp-83.json +21 -0
- package/public/r/comp-84.json +21 -0
- package/public/r/comp-85.json +22 -0
- package/public/r/comp-86.json +22 -0
- package/public/r/comp-87.json +21 -0
- package/public/r/comp-88.json +22 -0
- package/public/r/comp-89.json +21 -0
- package/public/r/comp-90.json +22 -0
- package/public/r/comp-91.json +22 -0
- package/public/r/comp-92.json +22 -0
- package/public/r/comp-93.json +22 -0
- package/public/r/comp-94.json +24 -0
- package/public/r/comp-95.json +26 -0
- package/public/r/comp-96.json +21 -0
- package/public/r/comp-97.json +21 -0
- package/public/r/comp-98.json +22 -0
- package/public/r/comp-99.json +23 -0
- package/public/r/comparison-event-handlers.json +1 -1
- package/public/r/comparison-hover.json +1 -1
- package/public/r/comparison.json +1 -1
- package/public/r/context-menu.json +16 -0
- package/public/r/contribution-graph-custom-footer.json +1 -1
- package/public/r/credit-card-apple.json +1 -1
- package/public/r/credit-card-back.json +1 -1
- package/public/r/credit-card.json +1 -1
- package/public/r/cropper.json +15 -0
- package/public/r/cursor-color.json +1 -1
- package/public/r/cursor-message.json +1 -1
- package/public/r/cursor-name-message.json +1 -1
- package/public/r/cursor-name.json +1 -1
- package/public/r/cursor.json +1 -1
- package/public/r/dashboard-1.json +263 -0
- package/public/r/dashboard-2.json +264 -0
- package/public/r/dashboard-3.json +225 -0
- package/public/r/datefield-rac.json +15 -0
- package/public/r/deck-controlled.json +1 -1
- package/public/r/deck-product-cards.json +1 -1
- package/public/r/deck.json +1 -1
- package/public/r/dialog-close-confirmation.json +1 -1
- package/public/r/dialog-demo.json +1 -1
- package/public/r/dialog-from-menu.json +1 -1
- package/public/r/dialog-nested.json +1 -1
- package/public/r/dialog-stack-controlled.json +1 -1
- package/public/r/dialog-stack-navigation.json +1 -1
- package/public/r/dialog-stack-six.json +1 -1
- package/public/r/dialog-stack.json +1 -1
- package/public/r/dropdown-menu.json +15 -0
- package/public/r/dropzone-custom-empty-state.json +1 -1
- package/public/r/dropzone-image-preview.json +1 -1
- package/public/r/editor.json +1 -1
- package/public/r/emails.json +243 -0
- package/public/r/empty-demo.json +1 -1
- package/public/r/example-app-calendar.json +323 -0
- package/public/r/field-2.json +19 -0
- package/public/r/field-autocomplete.json +1 -1
- package/public/r/field-checkbox-group.json +1 -1
- package/public/r/field-checkbox.json +1 -1
- package/public/r/field-combobox-multiple.json +1 -1
- package/public/r/field-combobox.json +1 -1
- package/public/r/field-complete-form.json +1 -1
- package/public/r/field-demo.json +1 -1
- package/public/r/field-disabled.json +1 -1
- package/public/r/field-error.json +1 -1
- package/public/r/field-number-field.json +1 -1
- package/public/r/field-radio.json +1 -1
- package/public/r/field-required.json +1 -1
- package/public/r/field-select.json +1 -1
- package/public/r/field-slider.json +1 -1
- package/public/r/field-switch.json +1 -1
- package/public/r/field-textarea.json +1 -1
- package/public/r/field-validity.json +1 -1
- package/public/r/fieldset-demo.json +1 -1
- package/public/r/files.json +195 -0
- package/public/r/form-demo.json +1 -1
- package/public/r/form-zod.json +1 -1
- package/public/r/form.json +1 -1
- package/public/r/frame-demo.json +1 -1
- package/public/r/gantt-lanes.json +1 -1
- package/public/r/gantt-no-sidebar.json +1 -1
- package/public/r/gantt-read-only.json +1 -1
- package/public/r/gantt.json +1 -1
- package/public/r/glimpse-custom.json +1 -1
- package/public/r/glimpse.json +1 -1
- package/public/r/gooey-toast-demo.json +1 -1
- package/public/r/gooey-toast-promise.json +1 -1
- package/public/r/gooey-toast-states.json +1 -1
- package/public/r/gooey-toast-with-button.json +1 -1
- package/public/r/group-demo.json +1 -1
- package/public/r/group-with-input.json +1 -1
- package/public/r/hero.json +1 -1
- package/public/r/hover-card.json +15 -0
- package/public/r/image-crop-circular.json +1 -1
- package/public/r/image-crop-custom.json +1 -1
- package/public/r/image-crop.json +1 -1
- package/public/r/image-zoom-background.json +1 -1
- package/public/r/image-zoom-margin.json +1 -1
- package/public/r/image-zoom.json +1 -1
- package/public/r/input-demo.json +1 -1
- package/public/r/input-disabled.json +1 -1
- package/public/r/input-file.json +1 -1
- package/public/r/input-group.json +20 -0
- package/public/r/input-lg.json +1 -1
- package/public/r/input-sm.json +1 -1
- package/public/r/input-with-button.json +1 -1
- package/public/r/input-with-label.json +1 -1
- package/public/r/kanban-simple.json +1 -1
- package/public/r/kanban.json +1 -1
- package/public/r/kbd.json +12 -0
- package/public/r/leads.json +271 -0
- package/public/r/list-simple.json +1 -1
- package/public/r/list.json +1 -1
- package/public/r/maps.json +188 -0
- package/public/r/menu-checkbox.json +1 -1
- package/public/r/menu-close-on-click.json +1 -1
- package/public/r/menu-demo.json +1 -1
- package/public/r/menu-group-labels.json +1 -1
- package/public/r/menu-hover.json +1 -1
- package/public/r/menu-link.json +1 -1
- package/public/r/menu-nested.json +1 -1
- package/public/r/menu-radio-group.json +1 -1
- package/public/r/meter-demo.json +1 -1
- package/public/r/meter-with-formatted-value.json +1 -1
- package/public/r/meter-with-range.json +1 -1
- package/public/r/mini-calendar-controlled.json +1 -1
- package/public/r/multiselect.json +15 -0
- package/public/r/navigation-menu.json +12 -0
- package/public/r/number-field-form.json +1 -1
- package/public/r/number-field-with-label.json +1 -1
- package/public/r/number-field-with-scrub.json +1 -1
- package/public/r/number-field-with-step.json +1 -1
- package/public/r/pill-avatar-group.json +1 -1
- package/public/r/pill-delta.json +1 -1
- package/public/r/pill-icon.json +1 -1
- package/public/r/pill-indicator.json +1 -1
- package/public/r/pill-status.json +1 -1
- package/public/r/pill.json +1 -1
- package/public/r/popover-demo.json +1 -1
- package/public/r/popover-with-close.json +1 -1
- package/public/r/preview-card-demo.json +1 -1
- package/public/r/pricing.json +1 -1
- package/public/r/progress-with-formatted-value.json +1 -1
- package/public/r/progress-with-label-value.json +1 -1
- package/public/r/radio-group-card.json +1 -1
- package/public/r/radio-group-demo.json +1 -1
- package/public/r/radio-group-disabled.json +1 -1
- package/public/r/radio-group-form.json +1 -1
- package/public/r/radio-group-with-description.json +1 -1
- package/public/r/reel-custom.json +1 -1
- package/public/r/reel-images.json +1 -1
- package/public/r/reel-minimal.json +1 -1
- package/public/r/reel.json +1 -1
- package/public/r/registry.json +18217 -0
- package/public/r/relative-time-controlled.json +1 -1
- package/public/r/relative-time-format-date.json +1 -1
- package/public/r/relative-time-format-time.json +1 -1
- package/public/r/relative-time.json +1 -1
- package/public/r/rentals.json +187 -0
- package/public/r/roadmap.json +1 -1
- package/public/r/sandbox-no-file-explorer.json +1 -1
- package/public/r/sandbox.json +1 -1
- package/public/r/scroll-area-both.json +1 -1
- package/public/r/scroll-area-demo.json +1 -1
- package/public/r/scroll-area-horizontal.json +1 -1
- package/public/r/select-demo.json +1 -1
- package/public/r/select-disabled.json +1 -1
- package/public/r/select-form.json +1 -1
- package/public/r/select-lg.json +1 -1
- package/public/r/select-native.json +12 -0
- package/public/r/select-sm.json +1 -1
- package/public/r/select-with-groups.json +1 -1
- package/public/r/select-without-alignment.json +1 -1
- package/public/r/select.json +1 -1
- package/public/r/separator-demo.json +1 -1
- package/public/r/sheet-demo.json +1 -1
- package/public/r/sheet-position.json +1 -1
- package/public/r/sidebar-nav.json +22 -0
- package/public/r/skeleton-demo.json +1 -1
- package/public/r/skeleton.json +1 -1
- package/public/r/slider-form.json +1 -1
- package/public/r/slider-with-label-value.json +1 -1
- package/public/r/sonner.json +16 -0
- package/public/r/stats-card.json +22 -0
- package/public/r/status-custom.json +1 -1
- package/public/r/stepper.json +15 -0
- package/public/r/stories-images.json +1 -1
- package/public/r/switch-card.json +1 -1
- package/public/r/switch-demo.json +1 -1
- package/public/r/switch-disabled.json +1 -1
- package/public/r/switch-form.json +1 -1
- package/public/r/switch-with-description.json +1 -1
- package/public/r/table-demo.json +1 -1
- package/public/r/table-framed.json +1 -1
- package/public/r/table-simple.json +1 -1
- package/public/r/table.json +1 -1
- package/public/r/tabs-demo.json +1 -1
- package/public/r/tabs-underline-vertical.json +1 -1
- package/public/r/tabs-underline.json +1 -1
- package/public/r/tabs-vertical.json +1 -1
- package/public/r/tags-create.json +1 -1
- package/public/r/tags-filter.json +1 -1
- package/public/r/tags.json +1 -1
- package/public/r/template-auth-eight.json +28 -0
- package/public/r/template-auth-five.json +28 -0
- package/public/r/template-auth-four.json +29 -0
- package/public/r/template-auth-nine.json +28 -0
- package/public/r/template-auth-one.json +49 -0
- package/public/r/template-auth-seven.json +29 -0
- package/public/r/template-auth-six.json +28 -0
- package/public/r/template-auth-three.json +49 -0
- package/public/r/template-auth-two.json +44 -0
- package/public/r/template-hero-eight.json +83 -0
- package/public/r/template-hero-eleven.json +29 -0
- package/public/r/template-hero-five.json +35 -0
- package/public/r/template-hero-four.json +35 -0
- package/public/r/template-hero-fourteen.json +101 -0
- package/public/r/template-hero-nine.json +74 -0
- package/public/r/template-hero-one.json +90 -0
- package/public/r/template-hero-seven.json +83 -0
- package/public/r/template-hero-six.json +83 -0
- package/public/r/template-hero-ten.json +77 -0
- package/public/r/template-hero-thirteen.json +101 -0
- package/public/r/template-hero-three.json +35 -0
- package/public/r/template-hero-twelve.json +30 -0
- package/public/r/template-hero-two.json +96 -0
- package/public/r/template-logo-cloud-five.json +68 -0
- package/public/r/template-logo-cloud-four.json +71 -0
- package/public/r/template-logo-cloud-one.json +89 -0
- package/public/r/template-logo-cloud-three.json +71 -0
- package/public/r/template-logo-cloud-two.json +74 -0
- package/public/r/textarea-demo.json +1 -1
- package/public/r/textarea-disabled.json +1 -1
- package/public/r/textarea-form.json +1 -1
- package/public/r/textarea-lg.json +1 -1
- package/public/r/textarea-sm.json +1 -1
- package/public/r/textarea-with-label.json +1 -1
- package/public/r/ticker-inline.json +1 -1
- package/public/r/timeline.json +15 -0
- package/public/r/toast-demo.json +1 -1
- package/public/r/toast-heights.json +1 -1
- package/public/r/toast-loading.json +1 -1
- package/public/r/toast-promise.json +1 -1
- package/public/r/toast-with-action.json +1 -1
- package/public/r/toast-with-status.json +1 -1
- package/public/r/toggle-demo.json +1 -1
- package/public/r/toggle-disabled.json +1 -1
- package/public/r/toggle-group-demo.json +1 -1
- package/public/r/toggle-group-disabled.json +1 -1
- package/public/r/toggle-group-lg.json +1 -1
- package/public/r/toggle-group-multiple.json +1 -1
- package/public/r/toggle-group-outline-with-separator.json +1 -1
- package/public/r/toggle-group-outline.json +1 -1
- package/public/r/toggle-group-sm.json +1 -1
- package/public/r/toggle-group-with-disabled-item.json +1 -1
- package/public/r/toggle-icon-group.json +1 -1
- package/public/r/toggle-lg.json +1 -1
- package/public/r/toggle-outline.json +1 -1
- package/public/r/toggle-sm.json +1 -1
- package/public/r/toggle-with-icon.json +1 -1
- package/public/r/toolbar-demo.json +1 -1
- package/public/r/tooltip-demo.json +1 -1
- package/public/r/tooltip-grouped.json +1 -1
- package/public/r/tree-controlled.json +1 -1
- package/public/r/tree-custom-icons.json +1 -1
- package/public/r/tree-no-lines.json +1 -1
- package/public/r/tree-simple.json +1 -1
- package/public/r/tree.json +1 -1
- package/public/r/typography.json +1 -1
- package/public/r/ui.json +5 -0
- package/public/r/use-character-limit.json +12 -0
- package/public/r/use-file-upload.json +12 -0
- package/public/r/use-pagination.json +12 -0
- package/public/r/use-slider-with-input.json +12 -0
- package/public/r/use-toast.json +12 -0
- package/public/r/utils.json +16 -0
|
@@ -0,0 +1,36 @@
|
|
|
1
|
+
{
|
|
2
|
+
"$schema": "https://ui.shadcn.com/schema/registry-item.json",
|
|
3
|
+
"name": "comp-478",
|
|
4
|
+
"type": "registry:component",
|
|
5
|
+
"dependencies": [
|
|
6
|
+
"@tanstack/react-table"
|
|
7
|
+
],
|
|
8
|
+
"registryDependencies": [
|
|
9
|
+
"https://loveui.dev/building-blocks/r/checkbox.json",
|
|
10
|
+
"https://loveui.dev/building-blocks/r/input.json",
|
|
11
|
+
"https://loveui.dev/building-blocks/r/label.json",
|
|
12
|
+
"https://loveui.dev/building-blocks/r/select.json",
|
|
13
|
+
"https://loveui.dev/building-blocks/r/table.json"
|
|
14
|
+
],
|
|
15
|
+
"files": [
|
|
16
|
+
{
|
|
17
|
+
"path": "registry/default/components/comp-478.tsx",
|
|
18
|
+
"content": "\"use client\"\n\nimport { useId, useMemo, useState } from \"react\"\nimport {\n Column,\n ColumnDef,\n ColumnFiltersState,\n flexRender,\n getCoreRowModel,\n getFacetedMinMaxValues,\n getFacetedRowModel,\n getFacetedUniqueValues,\n getFilteredRowModel,\n getSortedRowModel,\n RowData,\n SortingState,\n useReactTable,\n} from \"@tanstack/react-table\"\nimport {\n ChevronDownIcon,\n ChevronUpIcon,\n ExternalLinkIcon,\n SearchIcon,\n} from \"lucide-react\"\n\nimport { cn } from \"@/registry/building-blocks/default/lib/utils\"\nimport { Checkbox } from \"@/registry/building-blocks/default/ui/checkbox\"\nimport { Input } from \"@/registry/building-blocks/default/ui/input\"\nimport { Label } from \"@/registry/building-blocks/default/ui/label\"\nimport {\n Select,\n SelectContent,\n SelectItem,\n SelectTrigger,\n SelectValue,\n} from \"@/registry/building-blocks/default/ui/select\"\nimport {\n Table,\n TableBody,\n TableCell,\n TableHead,\n TableHeader,\n TableRow,\n} from \"@/registry/building-blocks/default/ui/table\"\n\ndeclare module \"@tanstack/react-table\" {\n //allows us to define custom properties for our columns\n interface ColumnMeta<TData extends RowData, TValue> {\n filterVariant?: \"text\" | \"range\" | \"select\"\n }\n}\n\ntype Item = {\n id: string\n keyword: string\n intents: Array<\n \"Informational\" | \"Navigational\" | \"Commercial\" | \"Transactional\"\n >\n volume: number\n cpc: number\n traffic: number\n link: string\n}\n\nconst columns: ColumnDef<Item>[] = [\n {\n id: \"select\",\n header: ({ table }) => (\n <Checkbox\n checked={\n table.getIsAllPageRowsSelected() ||\n (table.getIsSomePageRowsSelected() && \"indeterminate\")\n }\n onCheckedChange={(value) => table.toggleAllPageRowsSelected(!!value)}\n aria-label=\"Select all\"\n />\n ),\n cell: ({ row }) => (\n <Checkbox\n checked={row.getIsSelected()}\n onCheckedChange={(value) => row.toggleSelected(!!value)}\n aria-label=\"Select row\"\n />\n ),\n },\n {\n header: \"Keyword\",\n accessorKey: \"keyword\",\n cell: ({ row }) => (\n <div className=\"font-medium\">{row.getValue(\"keyword\")}</div>\n ),\n },\n {\n header: \"Intents\",\n accessorKey: \"intents\",\n cell: ({ row }) => {\n const intents = row.getValue(\"intents\") as string[]\n return (\n <div className=\"flex gap-1\">\n {intents.map((intent) => {\n const styles = {\n Informational: \"bg-indigo-400/20 text-indigo-500\",\n Navigational: \"bg-emerald-400/20 text-emerald-500\",\n Commercial: \"bg-amber-400/20 text-amber-500\",\n Transactional: \"bg-rose-400/20 text-rose-500\",\n }[intent]\n\n return (\n <div\n key={intent}\n className={cn(\n \"flex size-5 items-center justify-center rounded text-xs font-medium\",\n styles\n )}\n >\n {intent.charAt(0)}\n </div>\n )\n })}\n </div>\n )\n },\n enableSorting: false,\n meta: {\n filterVariant: \"select\",\n },\n filterFn: (row, id, filterValue) => {\n const rowValue = row.getValue(id)\n return Array.isArray(rowValue) && rowValue.includes(filterValue)\n },\n },\n {\n header: \"Volume\",\n accessorKey: \"volume\",\n cell: ({ row }) => {\n const volume = parseInt(row.getValue(\"volume\"))\n return new Intl.NumberFormat(\"en-US\", {\n notation: \"compact\",\n maximumFractionDigits: 1,\n }).format(volume)\n },\n meta: {\n filterVariant: \"range\",\n },\n },\n {\n header: \"CPC\",\n accessorKey: \"cpc\",\n cell: ({ row }) => <div>${row.getValue(\"cpc\")}</div>,\n meta: {\n filterVariant: \"range\",\n },\n },\n {\n header: \"Traffic\",\n accessorKey: \"traffic\",\n cell: ({ row }) => {\n const traffic = parseInt(row.getValue(\"traffic\"))\n return new Intl.NumberFormat(\"en-US\", {\n notation: \"compact\",\n maximumFractionDigits: 1,\n }).format(traffic)\n },\n meta: {\n filterVariant: \"range\",\n },\n },\n {\n header: \"Link\",\n accessorKey: \"link\",\n cell: ({ row }) => (\n <a className=\"inline-flex items-center gap-1 hover:underline\" href=\"#\">\n {row.getValue(\"link\")} <ExternalLinkIcon size={12} aria-hidden=\"true\" />\n </a>\n ),\n enableSorting: false,\n },\n]\n\nconst items: Item[] = [\n {\n id: \"1\",\n keyword: \"react components\",\n intents: [\"Informational\", \"Navigational\"],\n volume: 2507,\n cpc: 2.5,\n traffic: 88,\n link: \"https://loveui.dev/building-blocks\",\n },\n {\n id: \"2\",\n keyword: \"buy react templates\",\n intents: [\"Commercial\", \"Transactional\"],\n volume: 1850,\n cpc: 4.75,\n traffic: 65,\n link: \"https://loveui.dev/building-blocks/input\",\n },\n {\n id: \"3\",\n keyword: \"react ui library\",\n intents: [\"Informational\", \"Commercial\"],\n volume: 3200,\n cpc: 3.25,\n traffic: 112,\n link: \"https://loveui.dev/building-blocks/badge\",\n },\n {\n id: \"4\",\n keyword: \"tailwind components download\",\n intents: [\"Transactional\"],\n volume: 890,\n cpc: 1.95,\n traffic: 45,\n link: \"https://loveui.dev/building-blocks/alert\",\n },\n {\n id: \"5\",\n keyword: \"react dashboard template free\",\n intents: [\"Commercial\", \"Transactional\"],\n volume: 4100,\n cpc: 5.5,\n traffic: 156,\n link: \"https://loveui.dev/building-blocks/tabs\",\n },\n {\n id: \"6\",\n keyword: \"how to use react components\",\n intents: [\"Informational\"],\n volume: 1200,\n cpc: 1.25,\n traffic: 42,\n link: \"https://loveui.dev/building-blocks/table\",\n },\n {\n id: \"7\",\n keyword: \"react ui kit premium\",\n intents: [\"Commercial\", \"Transactional\"],\n volume: 760,\n cpc: 6.8,\n traffic: 28,\n link: \"https://loveui.dev/building-blocks/avatar\",\n },\n {\n id: \"8\",\n keyword: \"react component documentation\",\n intents: [\"Informational\", \"Navigational\"],\n volume: 950,\n cpc: 1.8,\n traffic: 35,\n link: \"https://loveui.dev/building-blocks\",\n },\n]\n\nexport default function Component() {\n const [columnFilters, setColumnFilters] = useState<ColumnFiltersState>([])\n const [sorting, setSorting] = useState<SortingState>([\n {\n id: \"traffic\",\n desc: false,\n },\n ])\n\n const table = useReactTable({\n data: items,\n columns,\n state: {\n sorting,\n columnFilters,\n },\n onColumnFiltersChange: setColumnFilters,\n getCoreRowModel: getCoreRowModel(),\n getFilteredRowModel: getFilteredRowModel(), //client-side filtering\n getSortedRowModel: getSortedRowModel(),\n getFacetedRowModel: getFacetedRowModel(), // client-side faceting\n getFacetedUniqueValues: getFacetedUniqueValues(), // generate unique values for select filter/autocomplete\n getFacetedMinMaxValues: getFacetedMinMaxValues(), // generate min/max values for range filter\n onSortingChange: setSorting,\n enableSortingRemoval: false,\n })\n\n return (\n <div className=\"space-y-6\">\n {/* Filters */}\n <div className=\"flex flex-wrap gap-3\">\n {/* Search input */}\n <div className=\"w-44\">\n <Filter column={table.getColumn(\"keyword\")!} />\n </div>\n {/* Intents select */}\n <div className=\"w-36\">\n <Filter column={table.getColumn(\"intents\")!} />\n </div>\n {/* Volume inputs */}\n <div className=\"w-36\">\n <Filter column={table.getColumn(\"volume\")!} />\n </div>\n {/* CPC inputs */}\n <div className=\"w-36\">\n <Filter column={table.getColumn(\"cpc\")!} />\n </div>\n {/* Traffic inputs */}\n <div className=\"w-36\">\n <Filter column={table.getColumn(\"traffic\")!} />\n </div>\n </div>\n\n <Table>\n <TableHeader>\n {table.getHeaderGroups().map((headerGroup) => (\n <TableRow key={headerGroup.id} className=\"bg-muted/50\">\n {headerGroup.headers.map((header) => {\n return (\n <TableHead\n key={header.id}\n className=\"relative h-10 border-t select-none\"\n aria-sort={\n header.column.getIsSorted() === \"asc\"\n ? \"ascending\"\n : header.column.getIsSorted() === \"desc\"\n ? \"descending\"\n : \"none\"\n }\n >\n {header.isPlaceholder ? null : header.column.getCanSort() ? (\n <div\n className={cn(\n header.column.getCanSort() &&\n \"flex h-full cursor-pointer items-center justify-between gap-2 select-none\"\n )}\n onClick={header.column.getToggleSortingHandler()}\n onKeyDown={(e) => {\n // Enhanced keyboard handling for sorting\n if (\n header.column.getCanSort() &&\n (e.key === \"Enter\" || e.key === \" \")\n ) {\n e.preventDefault()\n header.column.getToggleSortingHandler()?.(e)\n }\n }}\n tabIndex={header.column.getCanSort() ? 0 : undefined}\n >\n {flexRender(\n header.column.columnDef.header,\n header.getContext()\n )}\n {{\n asc: (\n <ChevronUpIcon\n className=\"shrink-0 opacity-60\"\n size={16}\n aria-hidden=\"true\"\n />\n ),\n desc: (\n <ChevronDownIcon\n className=\"shrink-0 opacity-60\"\n size={16}\n aria-hidden=\"true\"\n />\n ),\n }[header.column.getIsSorted() as string] ?? (\n <span className=\"size-4\" aria-hidden=\"true\" />\n )}\n </div>\n ) : (\n flexRender(\n header.column.columnDef.header,\n header.getContext()\n )\n )}\n </TableHead>\n )\n })}\n </TableRow>\n ))}\n </TableHeader>\n <TableBody>\n {table.getRowModel().rows?.length ? (\n table.getRowModel().rows.map((row) => (\n <TableRow\n key={row.id}\n data-state={row.getIsSelected() && \"selected\"}\n >\n {row.getVisibleCells().map((cell) => (\n <TableCell key={cell.id}>\n {flexRender(cell.column.columnDef.cell, cell.getContext())}\n </TableCell>\n ))}\n </TableRow>\n ))\n ) : (\n <TableRow>\n <TableCell colSpan={columns.length} className=\"h-24 text-center\">\n No results.\n </TableCell>\n </TableRow>\n )}\n </TableBody>\n </Table>\n <p className=\"mt-4 text-center text-sm text-muted-foreground\">\n Data table with filters made with{\" \"}\n <a\n className=\"underline hover:text-foreground\"\n href=\"https://tanstack.com/table\"\n target=\"_blank\"\n rel=\"noopener noreferrer\"\n >\n TanStack Table\n </a>\n </p>\n </div>\n )\n}\n\nfunction Filter({ column }: { column: Column<any, unknown> }) {\n const id = useId()\n const columnFilterValue = column.getFilterValue()\n const { filterVariant } = column.columnDef.meta ?? {}\n const columnHeader =\n typeof column.columnDef.header === \"string\" ? column.columnDef.header : \"\"\n const sortedUniqueValues = useMemo(() => {\n if (filterVariant === \"range\") return []\n\n // Get all unique values from the column\n const values = Array.from(column.getFacetedUniqueValues().keys())\n\n // If the values are arrays, flatten them and get unique items\n const flattenedValues = values.reduce((acc: string[], curr) => {\n if (Array.isArray(curr)) {\n return [...acc, ...curr]\n }\n return [...acc, curr]\n }, [])\n\n // Get unique values and sort them\n return Array.from(new Set(flattenedValues)).sort()\n }, [column.getFacetedUniqueValues(), filterVariant])\n\n if (filterVariant === \"range\") {\n return (\n <div className=\"*:not-first:mt-2\">\n <Label>{columnHeader}</Label>\n <div className=\"flex\">\n <Input\n id={`${id}-range-1`}\n className=\"flex-1 rounded-e-none [-moz-appearance:_textfield] focus:z-10 [&::-webkit-inner-spin-button]:m-0 [&::-webkit-inner-spin-button]:appearance-none [&::-webkit-outer-spin-button]:m-0 [&::-webkit-outer-spin-button]:appearance-none\"\n value={(columnFilterValue as [number, number])?.[0] ?? \"\"}\n onChange={(e) =>\n column.setFilterValue((old: [number, number]) => [\n e.target.value ? Number(e.target.value) : undefined,\n old?.[1],\n ])\n }\n placeholder=\"Min\"\n type=\"number\"\n aria-label={`${columnHeader} min`}\n />\n <Input\n id={`${id}-range-2`}\n className=\"-ms-px flex-1 rounded-s-none [-moz-appearance:_textfield] focus:z-10 [&::-webkit-inner-spin-button]:m-0 [&::-webkit-inner-spin-button]:appearance-none [&::-webkit-outer-spin-button]:m-0 [&::-webkit-outer-spin-button]:appearance-none\"\n value={(columnFilterValue as [number, number])?.[1] ?? \"\"}\n onChange={(e) =>\n column.setFilterValue((old: [number, number]) => [\n old?.[0],\n e.target.value ? Number(e.target.value) : undefined,\n ])\n }\n placeholder=\"Max\"\n type=\"number\"\n aria-label={`${columnHeader} max`}\n />\n </div>\n </div>\n )\n }\n\n if (filterVariant === \"select\") {\n return (\n <div className=\"*:not-first:mt-2\">\n <Label htmlFor={`${id}-select`}>{columnHeader}</Label>\n <Select\n value={columnFilterValue?.toString() ?? \"all\"}\n onValueChange={(value) => {\n column.setFilterValue(value === \"all\" ? undefined : value)\n }}\n >\n <SelectTrigger id={`${id}-select`}>\n <SelectValue />\n </SelectTrigger>\n <SelectContent>\n <SelectItem value=\"all\">All</SelectItem>\n {sortedUniqueValues.map((value) => (\n <SelectItem key={String(value)} value={String(value)}>\n {String(value)}\n </SelectItem>\n ))}\n </SelectContent>\n </Select>\n </div>\n )\n }\n\n return (\n <div className=\"*:not-first:mt-2\">\n <Label htmlFor={`${id}-input`}>{columnHeader}</Label>\n <div className=\"relative\">\n <Input\n id={`${id}-input`}\n className=\"peer ps-9\"\n value={(columnFilterValue ?? \"\") as string}\n onChange={(e) => column.setFilterValue(e.target.value)}\n placeholder={`Search ${columnHeader.toLowerCase()}`}\n type=\"text\"\n />\n <div className=\"pointer-events-none absolute inset-y-0 start-0 flex items-center justify-center ps-3 text-muted-foreground/80 peer-disabled:opacity-50\">\n <SearchIcon size={16} />\n </div>\n </div>\n </div>\n )\n}\n",
|
|
19
|
+
"type": "registry:component"
|
|
20
|
+
}
|
|
21
|
+
],
|
|
22
|
+
"meta": {
|
|
23
|
+
"tags": [
|
|
24
|
+
"table",
|
|
25
|
+
"tanstack",
|
|
26
|
+
"checkbox",
|
|
27
|
+
"search",
|
|
28
|
+
"select",
|
|
29
|
+
"range",
|
|
30
|
+
"input",
|
|
31
|
+
"filter",
|
|
32
|
+
"sort"
|
|
33
|
+
],
|
|
34
|
+
"colSpan": 3
|
|
35
|
+
}
|
|
36
|
+
}
|
|
@@ -0,0 +1,28 @@
|
|
|
1
|
+
{
|
|
2
|
+
"$schema": "https://ui.shadcn.com/schema/registry-item.json",
|
|
3
|
+
"name": "comp-479",
|
|
4
|
+
"type": "registry:component",
|
|
5
|
+
"dependencies": [
|
|
6
|
+
"@tanstack/react-table"
|
|
7
|
+
],
|
|
8
|
+
"registryDependencies": [
|
|
9
|
+
"https://loveui.dev/building-blocks/r/table.json"
|
|
10
|
+
],
|
|
11
|
+
"files": [
|
|
12
|
+
{
|
|
13
|
+
"path": "registry/default/components/comp-479.tsx",
|
|
14
|
+
"content": "\"use client\"\n\nimport { useEffect, useState } from \"react\"\nimport {\n ColumnDef,\n flexRender,\n getCoreRowModel,\n getSortedRowModel,\n SortingState,\n useReactTable,\n} from \"@tanstack/react-table\"\nimport { ChevronDownIcon, ChevronUpIcon } from \"lucide-react\"\n\nimport { cn } from \"@/registry/building-blocks/default/lib/utils\"\nimport {\n Table,\n TableBody,\n TableCell,\n TableHead,\n TableHeader,\n TableRow,\n} from \"@/registry/building-blocks/default/ui/table\"\n\ntype Item = {\n id: string\n name: string\n email: string\n location: string\n flag: string\n status: \"Active\" | \"Inactive\" | \"Pending\"\n balance: number\n department: string\n role: string\n joinDate: string\n lastActive: string\n performance: \"Excellent\" | \"Good\" | \"Average\" | \"Poor\"\n}\n\nconst columns: ColumnDef<Item>[] = [\n {\n header: \"Name\",\n accessorKey: \"name\",\n cell: ({ row }) => (\n <div className=\"truncate font-medium\">{row.getValue(\"name\")}</div>\n ),\n sortUndefined: \"last\",\n sortDescFirst: false,\n },\n {\n header: \"Email\",\n accessorKey: \"email\",\n },\n {\n header: \"Location\",\n accessorKey: \"location\",\n cell: ({ row }) => (\n <div className=\"truncate\">\n <span className=\"text-lg leading-none\">{row.original.flag}</span>{\" \"}\n {row.getValue(\"location\")}\n </div>\n ),\n },\n {\n header: \"Status\",\n accessorKey: \"status\",\n },\n {\n header: \"Balance\",\n accessorKey: \"balance\",\n cell: ({ row }) => {\n const amount = parseFloat(row.getValue(\"balance\"))\n const formatted = new Intl.NumberFormat(\"en-US\", {\n style: \"currency\",\n currency: \"USD\",\n }).format(amount)\n return formatted\n },\n },\n {\n header: \"Department\",\n accessorKey: \"department\",\n },\n {\n header: \"Role\",\n accessorKey: \"role\",\n },\n {\n header: \"Join Date\",\n accessorKey: \"joinDate\",\n },\n {\n header: \"Last Active\",\n accessorKey: \"lastActive\",\n },\n {\n header: \"Performance\",\n accessorKey: \"performance\",\n },\n]\n\nexport default function Component() {\n const [data, setData] = useState<Item[]>([])\n const [sorting, setSorting] = useState<SortingState>([\n {\n id: \"name\",\n desc: false,\n },\n ])\n\n useEffect(() => {\n async function fetchPosts() {\n const res = await fetch(\n \"https://raw.githubusercontent.com/origin-space/origin-images/refs/heads/main/users-01_fertyx.json\"\n )\n const data = await res.json()\n setData(data.slice(0, 5)) // Limit to 5 items\n }\n fetchPosts()\n }, [])\n\n const table = useReactTable({\n data,\n columns,\n columnResizeMode: \"onChange\",\n getCoreRowModel: getCoreRowModel(),\n getSortedRowModel: getSortedRowModel(),\n onSortingChange: setSorting,\n state: {\n sorting,\n },\n enableSortingRemoval: false,\n })\n\n return (\n <div>\n <Table\n className=\"table-fixed\"\n style={{\n width: table.getCenterTotalSize(),\n }}\n >\n <TableHeader>\n {table.getHeaderGroups().map((headerGroup) => (\n <TableRow key={headerGroup.id} className=\"bg-muted/50\">\n {headerGroup.headers.map((header) => {\n return (\n <TableHead\n key={header.id}\n className=\"relative h-10 border-t select-none last:[&>.cursor-col-resize]:opacity-0\"\n aria-sort={\n header.column.getIsSorted() === \"asc\"\n ? \"ascending\"\n : header.column.getIsSorted() === \"desc\"\n ? \"descending\"\n : \"none\"\n }\n {...{\n colSpan: header.colSpan,\n style: {\n width: header.getSize(),\n },\n }}\n >\n {header.isPlaceholder ? null : (\n <div\n className={cn(\n header.column.getCanSort() &&\n \"flex h-full cursor-pointer items-center justify-between gap-2 select-none\"\n )}\n onClick={header.column.getToggleSortingHandler()}\n onKeyDown={(e) => {\n // Enhanced keyboard handling for sorting\n if (\n header.column.getCanSort() &&\n (e.key === \"Enter\" || e.key === \" \")\n ) {\n e.preventDefault()\n header.column.getToggleSortingHandler()?.(e)\n }\n }}\n tabIndex={header.column.getCanSort() ? 0 : undefined}\n >\n <span className=\"truncate\">\n {flexRender(\n header.column.columnDef.header,\n header.getContext()\n )}\n </span>\n {{\n asc: (\n <ChevronUpIcon\n className=\"shrink-0 opacity-60\"\n size={16}\n aria-hidden=\"true\"\n />\n ),\n desc: (\n <ChevronDownIcon\n className=\"shrink-0 opacity-60\"\n size={16}\n aria-hidden=\"true\"\n />\n ),\n }[header.column.getIsSorted() as string] ?? null}\n </div>\n )}\n {header.column.getCanResize() && (\n <div\n {...{\n onDoubleClick: () => header.column.resetSize(),\n onMouseDown: header.getResizeHandler(),\n onTouchStart: header.getResizeHandler(),\n className:\n \"absolute top-0 h-full w-4 cursor-col-resize user-select-none touch-none -right-2 z-10 flex justify-center before:absolute before:w-px before:inset-y-0 before:bg-border before:translate-x-px\",\n }}\n />\n )}\n </TableHead>\n )\n })}\n </TableRow>\n ))}\n </TableHeader>\n <TableBody>\n {table.getRowModel().rows?.length ? (\n table.getRowModel().rows.map((row) => (\n <TableRow\n key={row.id}\n data-state={row.getIsSelected() && \"selected\"}\n >\n {row.getVisibleCells().map((cell) => (\n <TableCell key={cell.id} className=\"truncate\">\n {flexRender(cell.column.columnDef.cell, cell.getContext())}\n </TableCell>\n ))}\n </TableRow>\n ))\n ) : (\n <TableRow>\n <TableCell colSpan={columns.length} className=\"h-24 text-center\">\n No results.\n </TableCell>\n </TableRow>\n )}\n </TableBody>\n </Table>\n <p className=\"mt-4 text-center text-sm text-muted-foreground\">\n Resizable and sortable columns made with{\" \"}\n <a\n className=\"underline hover:text-foreground\"\n href=\"https://tanstack.com/table\"\n target=\"_blank\"\n rel=\"noopener noreferrer\"\n >\n TanStack Table\n </a>\n </p>\n </div>\n )\n}\n",
|
|
15
|
+
"type": "registry:component"
|
|
16
|
+
}
|
|
17
|
+
],
|
|
18
|
+
"meta": {
|
|
19
|
+
"tags": [
|
|
20
|
+
"table",
|
|
21
|
+
"tanstack",
|
|
22
|
+
"flag",
|
|
23
|
+
"sort",
|
|
24
|
+
"resize"
|
|
25
|
+
],
|
|
26
|
+
"colSpan": 3
|
|
27
|
+
}
|
|
28
|
+
}
|
|
@@ -0,0 +1,32 @@
|
|
|
1
|
+
{
|
|
2
|
+
"$schema": "https://ui.shadcn.com/schema/registry-item.json",
|
|
3
|
+
"name": "comp-48",
|
|
4
|
+
"type": "registry:component",
|
|
5
|
+
"dependencies": [
|
|
6
|
+
"react-payment-inputs"
|
|
7
|
+
],
|
|
8
|
+
"devDependencies": [
|
|
9
|
+
"@types/react-payment-inputs"
|
|
10
|
+
],
|
|
11
|
+
"registryDependencies": [
|
|
12
|
+
"https://loveui.dev/building-blocks/r/input.json",
|
|
13
|
+
"https://loveui.dev/building-blocks/r/label.json"
|
|
14
|
+
],
|
|
15
|
+
"files": [
|
|
16
|
+
{
|
|
17
|
+
"path": "registry/default/components/comp-48.tsx",
|
|
18
|
+
"content": "\"use client\"\n\nimport { useId } from \"react\"\nimport { usePaymentInputs } from \"react-payment-inputs\"\n\nimport { Input } from \"@/registry/building-blocks/default/ui/input\"\nimport { Label } from \"@/registry/building-blocks/default/ui/label\"\n\nexport default function Component() {\n const id = useId()\n const { getExpiryDateProps } = usePaymentInputs()\n\n return (\n <div className=\"*:not-first:mt-2\">\n <Label htmlFor={`expiry-${id}`}>Expiry date</Label>\n <Input\n {...getExpiryDateProps()}\n id={`expiry-${id}`}\n className=\"[direction:inherit]\"\n />\n <p\n className=\"mt-2 text-xs text-muted-foreground\"\n role=\"region\"\n aria-live=\"polite\"\n >\n Built with{\" \"}\n <a\n className=\"underline hover:text-foreground\"\n href=\"https://github.com/medipass/react-payment-inputs\"\n target=\"_blank\"\n rel=\"noopener nofollow\"\n >\n React Payment Inputs\n </a>\n </p>\n </div>\n )\n}\n",
|
|
19
|
+
"type": "registry:component"
|
|
20
|
+
}
|
|
21
|
+
],
|
|
22
|
+
"meta": {
|
|
23
|
+
"tags": [
|
|
24
|
+
"input",
|
|
25
|
+
"label",
|
|
26
|
+
"checkout",
|
|
27
|
+
"payment",
|
|
28
|
+
"credit card",
|
|
29
|
+
"form"
|
|
30
|
+
]
|
|
31
|
+
}
|
|
32
|
+
}
|
|
@@ -0,0 +1,30 @@
|
|
|
1
|
+
{
|
|
2
|
+
"$schema": "https://ui.shadcn.com/schema/registry-item.json",
|
|
3
|
+
"name": "comp-480",
|
|
4
|
+
"type": "registry:component",
|
|
5
|
+
"dependencies": [
|
|
6
|
+
"@tanstack/react-table"
|
|
7
|
+
],
|
|
8
|
+
"registryDependencies": [
|
|
9
|
+
"https://loveui.dev/building-blocks/r/button.json",
|
|
10
|
+
"https://loveui.dev/building-blocks/r/dropdown-menu.json",
|
|
11
|
+
"https://loveui.dev/building-blocks/r/table.json"
|
|
12
|
+
],
|
|
13
|
+
"files": [
|
|
14
|
+
{
|
|
15
|
+
"path": "registry/default/components/comp-480.tsx",
|
|
16
|
+
"content": "\"use client\"\n\nimport { CSSProperties, useEffect, useState } from \"react\"\nimport {\n Column,\n ColumnDef,\n flexRender,\n getCoreRowModel,\n getSortedRowModel,\n SortingState,\n useReactTable,\n} from \"@tanstack/react-table\"\nimport {\n ArrowLeftToLineIcon,\n ArrowRightToLineIcon,\n EllipsisIcon,\n PinOffIcon,\n} from \"lucide-react\"\n\nimport { Button } from \"@/registry/building-blocks/default/ui/button\"\nimport {\n DropdownMenu,\n DropdownMenuContent,\n DropdownMenuItem,\n DropdownMenuTrigger,\n} from \"@/registry/building-blocks/default/ui/dropdown-menu\"\nimport {\n Table,\n TableBody,\n TableCell,\n TableHead,\n TableHeader,\n TableRow,\n} from \"@/registry/building-blocks/default/ui/table\"\n\ntype Item = {\n id: string\n name: string\n email: string\n location: string\n flag: string\n status: \"Active\" | \"Inactive\" | \"Pending\"\n balance: number\n department: string\n role: string\n joinDate: string\n lastActive: string\n performance: \"Good\" | \"Very Good\" | \"Excellent\" | \"Outstanding\"\n}\n\n// Helper function to compute pinning styles for columns\nconst getPinningStyles = (column: Column<Item>): CSSProperties => {\n const isPinned = column.getIsPinned()\n return {\n left: isPinned === \"left\" ? `${column.getStart(\"left\")}px` : undefined,\n right: isPinned === \"right\" ? `${column.getAfter(\"right\")}px` : undefined,\n position: isPinned ? \"sticky\" : \"relative\",\n width: column.getSize(),\n zIndex: isPinned ? 1 : 0,\n }\n}\n\nconst columns: ColumnDef<Item>[] = [\n {\n header: \"Name\",\n accessorKey: \"name\",\n cell: ({ row }) => (\n <div className=\"truncate font-medium\">{row.getValue(\"name\")}</div>\n ),\n },\n {\n header: \"Email\",\n accessorKey: \"email\",\n },\n {\n header: \"Location\",\n accessorKey: \"location\",\n cell: ({ row }) => (\n <div className=\"truncate\">\n <span className=\"text-lg leading-none\">{row.original.flag}</span>{\" \"}\n {row.getValue(\"location\")}\n </div>\n ),\n },\n {\n header: \"Status\",\n accessorKey: \"status\",\n },\n {\n header: \"Balance\",\n accessorKey: \"balance\",\n cell: ({ row }) => {\n const amount = parseFloat(row.getValue(\"balance\"))\n const formatted = new Intl.NumberFormat(\"en-US\", {\n style: \"currency\",\n currency: \"USD\",\n }).format(amount)\n return formatted\n },\n },\n {\n header: \"Department\",\n accessorKey: \"department\",\n },\n {\n header: \"Role\",\n accessorKey: \"role\",\n },\n {\n header: \"Join Date\",\n accessorKey: \"joinDate\",\n },\n {\n header: \"Last Active\",\n accessorKey: \"lastActive\",\n },\n {\n header: \"Performance\",\n accessorKey: \"performance\",\n },\n]\n\nexport default function Component() {\n const [data, setData] = useState<Item[]>([])\n const [sorting, setSorting] = useState<SortingState>([])\n\n useEffect(() => {\n async function fetchPosts() {\n const res = await fetch(\n \"https://raw.githubusercontent.com/origin-space/origin-images/refs/heads/main/users-01_fertyx.json\"\n )\n const data = await res.json()\n setData(data.slice(0, 5)) // Limit to 5 items\n }\n fetchPosts()\n }, [])\n\n const table = useReactTable({\n data,\n columns,\n columnResizeMode: \"onChange\",\n getCoreRowModel: getCoreRowModel(),\n getSortedRowModel: getSortedRowModel(),\n onSortingChange: setSorting,\n state: {\n sorting,\n },\n enableSortingRemoval: false,\n })\n\n return (\n <div>\n <Table\n className=\"table-fixed border-separate border-spacing-0 [&_td]:border-border [&_tfoot_td]:border-t [&_th]:border-b [&_th]:border-border [&_tr]:border-none [&_tr:not(:last-child)_td]:border-b\"\n style={{\n width: table.getTotalSize(),\n }}\n >\n <TableHeader>\n {table.getHeaderGroups().map((headerGroup) => (\n <TableRow key={headerGroup.id} className=\"bg-muted/50\">\n {headerGroup.headers.map((header) => {\n const { column } = header\n const isPinned = column.getIsPinned()\n const isLastLeftPinned =\n isPinned === \"left\" && column.getIsLastColumn(\"left\")\n const isFirstRightPinned =\n isPinned === \"right\" && column.getIsFirstColumn(\"right\")\n\n return (\n <TableHead\n key={header.id}\n className=\"relative h-10 truncate border-t data-pinned:bg-muted/90 data-pinned:backdrop-blur-xs [&:not([data-pinned]):has(+[data-pinned])_div.cursor-col-resize:last-child]:opacity-0 [&[data-last-col=left]_div.cursor-col-resize:last-child]:opacity-0 [&[data-pinned=left][data-last-col=left]]:border-r [&[data-pinned=right]:last-child_div.cursor-col-resize:last-child]:opacity-0 [&[data-pinned=right][data-last-col=right]]:border-l [&[data-pinned][data-last-col]]:border-border\"\n colSpan={header.colSpan}\n style={{ ...getPinningStyles(column) }}\n data-pinned={isPinned || undefined}\n data-last-col={\n isLastLeftPinned\n ? \"left\"\n : isFirstRightPinned\n ? \"right\"\n : undefined\n }\n >\n <div className=\"flex items-center justify-between gap-2\">\n <span className=\"truncate\">\n {header.isPlaceholder\n ? null\n : flexRender(\n header.column.columnDef.header,\n header.getContext()\n )}\n </span>\n {/* Pin/Unpin column controls with enhanced accessibility */}\n {!header.isPlaceholder &&\n header.column.getCanPin() &&\n (header.column.getIsPinned() ? (\n <Button\n size=\"icon\"\n variant=\"ghost\"\n className=\"-mr-1 size-7 shadow-none\"\n onClick={() => header.column.pin(false)}\n aria-label={`Unpin ${header.column.columnDef.header as string} column`}\n title={`Unpin ${header.column.columnDef.header as string} column`}\n >\n <PinOffIcon\n className=\"opacity-60\"\n size={16}\n aria-hidden=\"true\"\n />\n </Button>\n ) : (\n <DropdownMenu>\n <DropdownMenuTrigger asChild>\n <Button\n size=\"icon\"\n variant=\"ghost\"\n className=\"-mr-1 size-7 shadow-none\"\n aria-label={`Pin options for ${header.column.columnDef.header as string} column`}\n title={`Pin options for ${header.column.columnDef.header as string} column`}\n >\n <EllipsisIcon\n className=\"opacity-60\"\n size={16}\n aria-hidden=\"true\"\n />\n </Button>\n </DropdownMenuTrigger>\n <DropdownMenuContent align=\"end\">\n <DropdownMenuItem\n onClick={() => header.column.pin(\"left\")}\n >\n <ArrowLeftToLineIcon\n size={16}\n className=\"opacity-60\"\n aria-hidden=\"true\"\n />\n Stick to left\n </DropdownMenuItem>\n <DropdownMenuItem\n onClick={() => header.column.pin(\"right\")}\n >\n <ArrowRightToLineIcon\n size={16}\n className=\"opacity-60\"\n aria-hidden=\"true\"\n />\n Stick to right\n </DropdownMenuItem>\n </DropdownMenuContent>\n </DropdownMenu>\n ))}\n {header.column.getCanResize() && (\n <div\n {...{\n onDoubleClick: () => header.column.resetSize(),\n onMouseDown: header.getResizeHandler(),\n onTouchStart: header.getResizeHandler(),\n className:\n \"absolute top-0 h-full w-4 cursor-col-resize user-select-none touch-none -right-2 z-10 flex justify-center before:absolute before:w-px before:inset-y-0 before:bg-border before:-translate-x-px\",\n }}\n />\n )}\n </div>\n </TableHead>\n )\n })}\n </TableRow>\n ))}\n </TableHeader>\n <TableBody>\n {table.getRowModel().rows?.length ? (\n table.getRowModel().rows.map((row) => (\n <TableRow\n key={row.id}\n data-state={row.getIsSelected() && \"selected\"}\n >\n {row.getVisibleCells().map((cell) => {\n const { column } = cell\n const isPinned = column.getIsPinned()\n const isLastLeftPinned =\n isPinned === \"left\" && column.getIsLastColumn(\"left\")\n const isFirstRightPinned =\n isPinned === \"right\" && column.getIsFirstColumn(\"right\")\n\n return (\n <TableCell\n key={cell.id}\n className=\"truncate data-pinned:bg-background/90 data-pinned:backdrop-blur-xs [&[data-pinned=left][data-last-col=left]]:border-r [&[data-pinned=right][data-last-col=right]]:border-l [&[data-pinned][data-last-col]]:border-border\"\n style={{ ...getPinningStyles(column) }}\n data-pinned={isPinned || undefined}\n data-last-col={\n isLastLeftPinned\n ? \"left\"\n : isFirstRightPinned\n ? \"right\"\n : undefined\n }\n >\n {flexRender(\n cell.column.columnDef.cell,\n cell.getContext()\n )}\n </TableCell>\n )\n })}\n </TableRow>\n ))\n ) : (\n <TableRow>\n <TableCell colSpan={columns.length} className=\"h-24 text-center\">\n No results.\n </TableCell>\n </TableRow>\n )}\n </TableBody>\n </Table>\n <p className=\"mt-4 text-center text-sm text-muted-foreground\">\n Pinnable columns made with{\" \"}\n <a\n className=\"underline hover:text-foreground\"\n href=\"https://tanstack.com/table\"\n target=\"_blank\"\n rel=\"noopener noreferrer\"\n >\n TanStack Table\n </a>\n </p>\n </div>\n )\n}\n",
|
|
17
|
+
"type": "registry:component"
|
|
18
|
+
}
|
|
19
|
+
],
|
|
20
|
+
"meta": {
|
|
21
|
+
"tags": [
|
|
22
|
+
"table",
|
|
23
|
+
"tanstack",
|
|
24
|
+
"flag",
|
|
25
|
+
"sticky",
|
|
26
|
+
"resize"
|
|
27
|
+
],
|
|
28
|
+
"colSpan": 3
|
|
29
|
+
}
|
|
30
|
+
}
|
|
@@ -0,0 +1,34 @@
|
|
|
1
|
+
{
|
|
2
|
+
"$schema": "https://ui.shadcn.com/schema/registry-item.json",
|
|
3
|
+
"name": "comp-481",
|
|
4
|
+
"type": "registry:component",
|
|
5
|
+
"dependencies": [
|
|
6
|
+
"@dnd-kit/core",
|
|
7
|
+
"@dnd-kit/modifiers",
|
|
8
|
+
"@dnd-kit/sortable",
|
|
9
|
+
"@dnd-kit/utilities",
|
|
10
|
+
"@tanstack/react-table"
|
|
11
|
+
],
|
|
12
|
+
"registryDependencies": [
|
|
13
|
+
"https://loveui.dev/building-blocks/r/button.json",
|
|
14
|
+
"https://loveui.dev/building-blocks/r/dropdown-menu.json",
|
|
15
|
+
"https://loveui.dev/building-blocks/r/table.json"
|
|
16
|
+
],
|
|
17
|
+
"files": [
|
|
18
|
+
{
|
|
19
|
+
"path": "registry/default/components/comp-481.tsx",
|
|
20
|
+
"content": "\"use client\"\n\nimport { CSSProperties, useEffect, useId, useState } from \"react\"\nimport {\n closestCenter,\n DndContext,\n KeyboardSensor,\n MouseSensor,\n TouchSensor,\n useSensor,\n useSensors,\n type DragEndEvent,\n} from \"@dnd-kit/core\"\nimport { restrictToHorizontalAxis } from \"@dnd-kit/modifiers\"\nimport {\n arrayMove,\n horizontalListSortingStrategy,\n SortableContext,\n useSortable,\n} from \"@dnd-kit/sortable\"\nimport { CSS } from \"@dnd-kit/utilities\"\nimport {\n Cell,\n ColumnDef,\n flexRender,\n getCoreRowModel,\n getSortedRowModel,\n Header,\n SortingState,\n useReactTable,\n} from \"@tanstack/react-table\"\nimport { ChevronDownIcon, ChevronUpIcon, GripVerticalIcon } from \"lucide-react\"\n\nimport { Button } from \"@/registry/building-blocks/default/ui/button\"\nimport {\n Table,\n TableBody,\n TableCell,\n TableHead,\n TableHeader,\n TableRow,\n} from \"@/registry/building-blocks/default/ui/table\"\n\ntype Item = {\n id: string\n name: string\n email: string\n location: string\n flag: string\n status: \"Active\" | \"Inactive\" | \"Pending\"\n balance: number\n}\n\nconst columns: ColumnDef<Item>[] = [\n {\n id: \"name\",\n header: \"Name\",\n accessorKey: \"name\",\n cell: ({ row }) => (\n <div className=\"truncate font-medium\">{row.getValue(\"name\")}</div>\n ),\n sortUndefined: \"last\",\n sortDescFirst: false,\n },\n {\n id: \"email\",\n header: \"Email\",\n accessorKey: \"email\",\n },\n {\n id: \"location\",\n header: \"Location\",\n accessorKey: \"location\",\n cell: ({ row }) => (\n <div className=\"truncate\">\n <span className=\"text-lg leading-none\">{row.original.flag}</span>{\" \"}\n {row.getValue(\"location\")}\n </div>\n ),\n },\n {\n id: \"status\",\n header: \"Status\",\n accessorKey: \"status\",\n },\n {\n id: \"balance\",\n header: \"Balance\",\n accessorKey: \"balance\",\n cell: ({ row }) => {\n const amount = parseFloat(row.getValue(\"balance\"))\n const formatted = new Intl.NumberFormat(\"en-US\", {\n style: \"currency\",\n currency: \"USD\",\n }).format(amount)\n return formatted\n },\n },\n]\n\nexport default function Component() {\n const [data, setData] = useState<Item[]>([])\n const [sorting, setSorting] = useState<SortingState>([])\n const [columnOrder, setColumnOrder] = useState<string[]>(\n columns.map((column) => column.id as string)\n )\n\n useEffect(() => {\n async function fetchPosts() {\n const res = await fetch(\n \"https://raw.githubusercontent.com/origin-space/origin-images/refs/heads/main/users-01_fertyx.json\"\n )\n const data = await res.json()\n setData(data.slice(0, 5)) // Limit to 5 items\n }\n fetchPosts()\n }, [])\n\n const table = useReactTable({\n data,\n columns,\n columnResizeMode: \"onChange\",\n getCoreRowModel: getCoreRowModel(),\n getSortedRowModel: getSortedRowModel(),\n onSortingChange: setSorting,\n state: {\n sorting,\n columnOrder,\n },\n onColumnOrderChange: setColumnOrder,\n enableSortingRemoval: false,\n })\n\n // reorder columns after drag & drop\n function handleDragEnd(event: DragEndEvent) {\n const { active, over } = event\n if (active && over && active.id !== over.id) {\n setColumnOrder((columnOrder) => {\n const oldIndex = columnOrder.indexOf(active.id as string)\n const newIndex = columnOrder.indexOf(over.id as string)\n return arrayMove(columnOrder, oldIndex, newIndex) //this is just a splice util\n })\n }\n }\n\n const sensors = useSensors(\n useSensor(MouseSensor, {}),\n useSensor(TouchSensor, {}),\n useSensor(KeyboardSensor, {})\n )\n\n return (\n <DndContext\n id={useId()}\n collisionDetection={closestCenter}\n modifiers={[restrictToHorizontalAxis]}\n onDragEnd={handleDragEnd}\n sensors={sensors}\n >\n <Table>\n <TableHeader>\n {table.getHeaderGroups().map((headerGroup) => (\n <TableRow key={headerGroup.id} className=\"bg-muted/50\">\n <SortableContext\n items={columnOrder}\n strategy={horizontalListSortingStrategy}\n >\n {headerGroup.headers.map((header) => (\n <DraggableTableHeader key={header.id} header={header} />\n ))}\n </SortableContext>\n </TableRow>\n ))}\n </TableHeader>\n <TableBody>\n {table.getRowModel().rows?.length ? (\n table.getRowModel().rows.map((row) => (\n <TableRow\n key={row.id}\n data-state={row.getIsSelected() && \"selected\"}\n >\n {row.getVisibleCells().map((cell) => (\n <SortableContext\n key={cell.id}\n items={columnOrder}\n strategy={horizontalListSortingStrategy}\n >\n <DragAlongCell key={cell.id} cell={cell} />\n </SortableContext>\n ))}\n </TableRow>\n ))\n ) : (\n <TableRow>\n <TableCell colSpan={columns.length} className=\"h-24 text-center\">\n No results.\n </TableCell>\n </TableRow>\n )}\n </TableBody>\n </Table>\n <p className=\"mt-4 text-center text-sm text-muted-foreground\">\n Draggable columns made with{\" \"}\n <a\n className=\"underline hover:text-foreground\"\n href=\"https://tanstack.com/table\"\n target=\"_blank\"\n rel=\"noopener noreferrer\"\n >\n TanStack Table\n </a>{\" \"}\n and{\" \"}\n <a href=\"https://dndkit.com/\" target=\"_blank\" rel=\"noopener noreferrer\">\n dnd kit\n </a>\n </p>\n </DndContext>\n )\n}\n\nconst DraggableTableHeader = ({\n header,\n}: {\n header: Header<Item, unknown>\n}) => {\n const {\n attributes,\n isDragging,\n listeners,\n setNodeRef,\n transform,\n transition,\n } = useSortable({\n id: header.column.id,\n })\n\n const style: CSSProperties = {\n opacity: isDragging ? 0.8 : 1,\n position: \"relative\",\n transform: CSS.Translate.toString(transform),\n transition,\n whiteSpace: \"nowrap\",\n width: header.column.getSize(),\n zIndex: isDragging ? 1 : 0,\n }\n\n return (\n <TableHead\n ref={setNodeRef}\n className=\"relative h-10 border-t before:absolute before:inset-y-0 before:start-0 before:w-px before:bg-border first:before:bg-transparent\"\n style={style}\n aria-sort={\n header.column.getIsSorted() === \"asc\"\n ? \"ascending\"\n : header.column.getIsSorted() === \"desc\"\n ? \"descending\"\n : \"none\"\n }\n >\n <div className=\"flex items-center justify-start gap-0.5\">\n <Button\n size=\"icon\"\n variant=\"ghost\"\n className=\"-ml-2 size-7 shadow-none\"\n {...attributes}\n {...listeners}\n aria-label=\"Drag to reorder\"\n >\n <GripVerticalIcon\n className=\"opacity-60\"\n size={16}\n aria-hidden=\"true\"\n />\n </Button>\n <span className=\"grow truncate\">\n {header.isPlaceholder\n ? null\n : flexRender(header.column.columnDef.header, header.getContext())}\n </span>\n <Button\n size=\"icon\"\n variant=\"ghost\"\n className=\"group -mr-1 size-7 shadow-none\"\n onClick={header.column.getToggleSortingHandler()}\n onKeyDown={(e) => {\n // Enhanced keyboard handling for sorting\n if (\n header.column.getCanSort() &&\n (e.key === \"Enter\" || e.key === \" \")\n ) {\n e.preventDefault()\n header.column.getToggleSortingHandler()?.(e)\n }\n }}\n >\n {{\n asc: (\n <ChevronUpIcon\n className=\"shrink-0 opacity-60\"\n size={16}\n aria-hidden=\"true\"\n />\n ),\n desc: (\n <ChevronDownIcon\n className=\"shrink-0 opacity-60\"\n size={16}\n aria-hidden=\"true\"\n />\n ),\n }[header.column.getIsSorted() as string] ?? (\n <ChevronUpIcon\n className=\"shrink-0 opacity-0 group-hover:opacity-60\"\n size={16}\n aria-hidden=\"true\"\n />\n )}\n </Button>\n </div>\n </TableHead>\n )\n}\n\nconst DragAlongCell = ({ cell }: { cell: Cell<Item, unknown> }) => {\n const { isDragging, setNodeRef, transform, transition } = useSortable({\n id: cell.column.id,\n })\n\n const style: CSSProperties = {\n opacity: isDragging ? 0.8 : 1,\n position: \"relative\",\n transform: CSS.Translate.toString(transform),\n transition,\n width: cell.column.getSize(),\n zIndex: isDragging ? 1 : 0,\n }\n\n return (\n <TableCell ref={setNodeRef} className=\"truncate\" style={style}>\n {flexRender(cell.column.columnDef.cell, cell.getContext())}\n </TableCell>\n )\n}\n",
|
|
21
|
+
"type": "registry:component"
|
|
22
|
+
}
|
|
23
|
+
],
|
|
24
|
+
"meta": {
|
|
25
|
+
"tags": [
|
|
26
|
+
"table",
|
|
27
|
+
"tanstack",
|
|
28
|
+
"flag",
|
|
29
|
+
"sort",
|
|
30
|
+
"drag and drop"
|
|
31
|
+
],
|
|
32
|
+
"colSpan": 3
|
|
33
|
+
}
|
|
34
|
+
}
|
|
@@ -0,0 +1,33 @@
|
|
|
1
|
+
{
|
|
2
|
+
"$schema": "https://ui.shadcn.com/schema/registry-item.json",
|
|
3
|
+
"name": "comp-482",
|
|
4
|
+
"type": "registry:component",
|
|
5
|
+
"dependencies": [
|
|
6
|
+
"@tanstack/react-table"
|
|
7
|
+
],
|
|
8
|
+
"registryDependencies": [
|
|
9
|
+
"https://loveui.dev/building-blocks/r/badge.json",
|
|
10
|
+
"https://loveui.dev/building-blocks/r/button.json",
|
|
11
|
+
"https://loveui.dev/building-blocks/r/checkbox.json",
|
|
12
|
+
"https://loveui.dev/building-blocks/r/table.json"
|
|
13
|
+
],
|
|
14
|
+
"files": [
|
|
15
|
+
{
|
|
16
|
+
"path": "registry/default/components/comp-482.tsx",
|
|
17
|
+
"content": "\"use client\"\n\nimport { Fragment, useEffect, useState } from \"react\"\nimport {\n ColumnDef,\n flexRender,\n getCoreRowModel,\n getExpandedRowModel,\n useReactTable,\n} from \"@tanstack/react-table\"\nimport { ChevronDownIcon, ChevronUpIcon, InfoIcon } from \"lucide-react\"\n\nimport { cn } from \"@/registry/building-blocks/default/lib/utils\"\nimport { Badge } from \"@/registry/building-blocks/default/ui/badge\"\nimport { Button } from \"@/registry/building-blocks/default/ui/button\"\nimport { Checkbox } from \"@/registry/building-blocks/default/ui/checkbox\"\nimport {\n Table,\n TableBody,\n TableCell,\n TableHead,\n TableHeader,\n TableRow,\n} from \"@/registry/building-blocks/default/ui/table\"\n\ntype Item = {\n id: string\n name: string\n email: string\n location: string\n flag: string\n status: \"Active\" | \"Inactive\" | \"Pending\"\n balance: number\n note?: string\n}\n\nconst columns: ColumnDef<Item>[] = [\n {\n id: \"expander\",\n header: () => null,\n cell: ({ row }) => {\n return row.getCanExpand() ? (\n <Button\n {...{\n className: \"size-7 shadow-none text-muted-foreground\",\n onClick: row.getToggleExpandedHandler(),\n \"aria-expanded\": row.getIsExpanded(),\n \"aria-label\": row.getIsExpanded()\n ? `Collapse details for ${row.original.name}`\n : `Expand details for ${row.original.name}`,\n size: \"icon\",\n variant: \"ghost\",\n }}\n >\n {row.getIsExpanded() ? (\n <ChevronUpIcon\n className=\"opacity-60\"\n size={16}\n aria-hidden=\"true\"\n />\n ) : (\n <ChevronDownIcon\n className=\"opacity-60\"\n size={16}\n aria-hidden=\"true\"\n />\n )}\n </Button>\n ) : undefined\n },\n },\n {\n id: \"select\",\n header: ({ table }) => (\n <Checkbox\n checked={\n table.getIsAllPageRowsSelected() ||\n (table.getIsSomePageRowsSelected() && \"indeterminate\")\n }\n onCheckedChange={(value) => table.toggleAllPageRowsSelected(!!value)}\n aria-label=\"Select all\"\n />\n ),\n cell: ({ row }) => (\n <Checkbox\n checked={row.getIsSelected()}\n onCheckedChange={(value) => row.toggleSelected(!!value)}\n aria-label=\"Select row\"\n />\n ),\n },\n {\n header: \"Name\",\n accessorKey: \"name\",\n cell: ({ row }) => (\n <div className=\"font-medium\">{row.getValue(\"name\")}</div>\n ),\n },\n {\n header: \"Email\",\n accessorKey: \"email\",\n },\n {\n header: \"Location\",\n accessorKey: \"location\",\n cell: ({ row }) => (\n <div>\n <span className=\"text-lg leading-none\">{row.original.flag}</span>{\" \"}\n {row.getValue(\"location\")}\n </div>\n ),\n },\n {\n header: \"Status\",\n accessorKey: \"status\",\n cell: ({ row }) => (\n <Badge\n className={cn(\n row.getValue(\"status\") === \"Inactive\" &&\n \"bg-muted-foreground/60 text-primary-foreground\"\n )}\n >\n {row.getValue(\"status\")}\n </Badge>\n ),\n },\n {\n header: () => <div className=\"text-right\">Balance</div>,\n accessorKey: \"balance\",\n cell: ({ row }) => {\n const amount = parseFloat(row.getValue(\"balance\"))\n const formatted = new Intl.NumberFormat(\"en-US\", {\n style: \"currency\",\n currency: \"USD\",\n }).format(amount)\n return <div className=\"text-right\">{formatted}</div>\n },\n },\n]\n\nexport default function Component() {\n const [data, setData] = useState<Item[]>([])\n\n useEffect(() => {\n async function fetchPosts() {\n const res = await fetch(\n \"https://raw.githubusercontent.com/origin-space/origin-images/refs/heads/main/users-01_fertyx.json\"\n )\n const data = await res.json()\n setData(data.slice(0, 5)) // Limit to 5 items\n }\n fetchPosts()\n }, [])\n\n const table = useReactTable({\n data,\n columns,\n getRowCanExpand: (row) => Boolean(row.original.note),\n getCoreRowModel: getCoreRowModel(),\n getExpandedRowModel: getExpandedRowModel(),\n })\n\n return (\n <div>\n <Table>\n <TableHeader>\n {table.getHeaderGroups().map((headerGroup) => (\n <TableRow key={headerGroup.id} className=\"hover:bg-transparent\">\n {headerGroup.headers.map((header) => {\n return (\n <TableHead key={header.id}>\n {header.isPlaceholder\n ? null\n : flexRender(\n header.column.columnDef.header,\n header.getContext()\n )}\n </TableHead>\n )\n })}\n </TableRow>\n ))}\n </TableHeader>\n <TableBody>\n {table.getRowModel().rows?.length ? (\n table.getRowModel().rows.map((row) => (\n <Fragment key={row.id}>\n <TableRow\n key={row.id}\n data-state={row.getIsSelected() && \"selected\"}\n >\n {row.getVisibleCells().map((cell) => (\n <TableCell\n key={cell.id}\n className=\"whitespace-nowrap [&:has([aria-expanded])]:w-px [&:has([aria-expanded])]:py-0 [&:has([aria-expanded])]:pr-0\"\n >\n {flexRender(\n cell.column.columnDef.cell,\n cell.getContext()\n )}\n </TableCell>\n ))}\n </TableRow>\n {row.getIsExpanded() && (\n <TableRow>\n <TableCell colSpan={row.getVisibleCells().length}>\n <div className=\"flex items-start py-2 text-primary/80\">\n <span\n className=\"me-3 mt-0.5 flex w-7 shrink-0 justify-center\"\n aria-hidden=\"true\"\n >\n <InfoIcon className=\"opacity-60\" size={16} />\n </span>\n <p className=\"text-sm\">{row.original.note}</p>\n </div>\n </TableCell>\n </TableRow>\n )}\n </Fragment>\n ))\n ) : (\n <TableRow>\n <TableCell colSpan={columns.length} className=\"h-24 text-center\">\n No results.\n </TableCell>\n </TableRow>\n )}\n </TableBody>\n </Table>\n <p className=\"mt-4 text-center text-sm text-muted-foreground\">\n Expanding sub-row made with{\" \"}\n <a\n className=\"underline hover:text-foreground\"\n href=\"https://tanstack.com/table\"\n target=\"_blank\"\n rel=\"noopener noreferrer\"\n >\n TanStack Table\n </a>\n </p>\n </div>\n )\n}\n",
|
|
18
|
+
"type": "registry:component"
|
|
19
|
+
}
|
|
20
|
+
],
|
|
21
|
+
"meta": {
|
|
22
|
+
"tags": [
|
|
23
|
+
"table",
|
|
24
|
+
"tanstack",
|
|
25
|
+
"checkbox",
|
|
26
|
+
"collapsible",
|
|
27
|
+
"flag",
|
|
28
|
+
"badge",
|
|
29
|
+
"chip"
|
|
30
|
+
],
|
|
31
|
+
"colSpan": 3
|
|
32
|
+
}
|
|
33
|
+
}
|
|
@@ -0,0 +1,37 @@
|
|
|
1
|
+
{
|
|
2
|
+
"$schema": "https://ui.shadcn.com/schema/registry-item.json",
|
|
3
|
+
"name": "comp-483",
|
|
4
|
+
"type": "registry:component",
|
|
5
|
+
"dependencies": [
|
|
6
|
+
"@tanstack/react-table"
|
|
7
|
+
],
|
|
8
|
+
"registryDependencies": [
|
|
9
|
+
"https://loveui.dev/building-blocks/r/badge.json",
|
|
10
|
+
"https://loveui.dev/building-blocks/r/button.json",
|
|
11
|
+
"https://loveui.dev/building-blocks/r/checkbox.json",
|
|
12
|
+
"https://loveui.dev/building-blocks/r/label.json",
|
|
13
|
+
"https://loveui.dev/building-blocks/r/pagination.json",
|
|
14
|
+
"https://loveui.dev/building-blocks/r/select.json",
|
|
15
|
+
"https://loveui.dev/building-blocks/r/table.json"
|
|
16
|
+
],
|
|
17
|
+
"files": [
|
|
18
|
+
{
|
|
19
|
+
"path": "registry/default/components/comp-483.tsx",
|
|
20
|
+
"content": "\"use client\"\n\nimport { useEffect, useId, useState } from \"react\"\nimport {\n ColumnDef,\n flexRender,\n getCoreRowModel,\n getPaginationRowModel,\n getSortedRowModel,\n PaginationState,\n SortingState,\n useReactTable,\n} from \"@tanstack/react-table\"\nimport {\n ChevronDownIcon,\n ChevronFirstIcon,\n ChevronLastIcon,\n ChevronLeftIcon,\n ChevronRightIcon,\n ChevronUpIcon,\n} from \"lucide-react\"\n\nimport { cn } from \"@/registry/building-blocks/default/lib/utils\"\nimport { Badge } from \"@/registry/building-blocks/default/ui/badge\"\nimport { Button } from \"@/registry/building-blocks/default/ui/button\"\nimport { Checkbox } from \"@/registry/building-blocks/default/ui/checkbox\"\nimport { Label } from \"@/registry/building-blocks/default/ui/label\"\nimport {\n Pagination,\n PaginationContent,\n PaginationItem,\n} from \"@/registry/building-blocks/default/ui/pagination\"\nimport {\n Select,\n SelectContent,\n SelectItem,\n SelectTrigger,\n SelectValue,\n} from \"@/registry/building-blocks/default/ui/select\"\nimport {\n Table,\n TableBody,\n TableCell,\n TableHead,\n TableHeader,\n TableRow,\n} from \"@/registry/building-blocks/default/ui/table\"\n\ntype Item = {\n id: string\n name: string\n email: string\n location: string\n flag: string\n status: \"Active\" | \"Inactive\" | \"Pending\"\n balance: number\n}\n\nconst columns: ColumnDef<Item>[] = [\n {\n id: \"select\",\n header: ({ table }) => (\n <Checkbox\n checked={\n table.getIsAllPageRowsSelected() ||\n (table.getIsSomePageRowsSelected() && \"indeterminate\")\n }\n onCheckedChange={(value) => table.toggleAllPageRowsSelected(!!value)}\n aria-label=\"Select all\"\n />\n ),\n cell: ({ row }) => (\n <Checkbox\n checked={row.getIsSelected()}\n onCheckedChange={(value) => row.toggleSelected(!!value)}\n aria-label=\"Select row\"\n />\n ),\n size: 28,\n enableSorting: false,\n },\n {\n header: \"Name\",\n accessorKey: \"name\",\n cell: ({ row }) => (\n <div className=\"font-medium\">{row.getValue(\"name\")}</div>\n ),\n size: 180,\n },\n {\n header: \"Email\",\n accessorKey: \"email\",\n size: 200,\n },\n {\n header: \"Location\",\n accessorKey: \"location\",\n cell: ({ row }) => (\n <div>\n <span className=\"text-lg leading-none\">{row.original.flag}</span>{\" \"}\n {row.getValue(\"location\")}\n </div>\n ),\n size: 180,\n },\n {\n header: \"Status\",\n accessorKey: \"status\",\n cell: ({ row }) => (\n <Badge\n className={cn(\n row.getValue(\"status\") === \"Inactive\" &&\n \"bg-muted-foreground/60 text-primary-foreground\"\n )}\n >\n {row.getValue(\"status\")}\n </Badge>\n ),\n size: 120,\n },\n {\n header: \"Balance\",\n accessorKey: \"balance\",\n cell: ({ row }) => {\n const amount = parseFloat(row.getValue(\"balance\"))\n const formatted = new Intl.NumberFormat(\"en-US\", {\n style: \"currency\",\n currency: \"USD\",\n }).format(amount)\n return formatted\n },\n size: 120,\n },\n]\n\nexport default function Component() {\n const id = useId()\n const [pagination, setPagination] = useState<PaginationState>({\n pageIndex: 0,\n pageSize: 5,\n })\n\n const [sorting, setSorting] = useState<SortingState>([\n {\n id: \"name\",\n desc: false,\n },\n ])\n\n const [data, setData] = useState<Item[]>([])\n useEffect(() => {\n async function fetchPosts() {\n const res = await fetch(\n \"https://raw.githubusercontent.com/origin-space/origin-images/refs/heads/main/users-01_fertyx.json\"\n )\n const data = await res.json()\n setData([...data, ...data])\n }\n fetchPosts()\n }, [])\n\n const table = useReactTable({\n data,\n columns,\n getCoreRowModel: getCoreRowModel(),\n getSortedRowModel: getSortedRowModel(),\n onSortingChange: setSorting,\n enableSortingRemoval: false,\n getPaginationRowModel: getPaginationRowModel(),\n onPaginationChange: setPagination,\n state: {\n sorting,\n pagination,\n },\n })\n\n return (\n <div className=\"space-y-4\">\n <div className=\"overflow-hidden rounded-md border bg-background\">\n <Table className=\"table-fixed\">\n <TableHeader>\n {table.getHeaderGroups().map((headerGroup) => (\n <TableRow key={headerGroup.id} className=\"hover:bg-transparent\">\n {headerGroup.headers.map((header) => {\n return (\n <TableHead\n key={header.id}\n style={{ width: `${header.getSize()}px` }}\n className=\"h-11\"\n >\n {header.isPlaceholder ? null : header.column.getCanSort() ? (\n <div\n className={cn(\n header.column.getCanSort() &&\n \"flex h-full cursor-pointer items-center justify-between gap-2 select-none\"\n )}\n onClick={header.column.getToggleSortingHandler()}\n onKeyDown={(e) => {\n // Enhanced keyboard handling for sorting\n if (\n header.column.getCanSort() &&\n (e.key === \"Enter\" || e.key === \" \")\n ) {\n e.preventDefault()\n header.column.getToggleSortingHandler()?.(e)\n }\n }}\n tabIndex={header.column.getCanSort() ? 0 : undefined}\n >\n {flexRender(\n header.column.columnDef.header,\n header.getContext()\n )}\n {{\n asc: (\n <ChevronUpIcon\n className=\"shrink-0 opacity-60\"\n size={16}\n aria-hidden=\"true\"\n />\n ),\n desc: (\n <ChevronDownIcon\n className=\"shrink-0 opacity-60\"\n size={16}\n aria-hidden=\"true\"\n />\n ),\n }[header.column.getIsSorted() as string] ?? null}\n </div>\n ) : (\n flexRender(\n header.column.columnDef.header,\n header.getContext()\n )\n )}\n </TableHead>\n )\n })}\n </TableRow>\n ))}\n </TableHeader>\n <TableBody>\n {table.getRowModel().rows?.length ? (\n table.getRowModel().rows.map((row) => (\n <TableRow\n key={row.id}\n data-state={row.getIsSelected() && \"selected\"}\n >\n {row.getVisibleCells().map((cell) => (\n <TableCell key={cell.id}>\n {flexRender(\n cell.column.columnDef.cell,\n cell.getContext()\n )}\n </TableCell>\n ))}\n </TableRow>\n ))\n ) : (\n <TableRow>\n <TableCell\n colSpan={columns.length}\n className=\"h-24 text-center\"\n >\n No results.\n </TableCell>\n </TableRow>\n )}\n </TableBody>\n </Table>\n </div>\n\n {/* Pagination */}\n <div className=\"flex items-center justify-between gap-8\">\n {/* Results per page */}\n <div className=\"flex items-center gap-3\">\n <Label htmlFor={id} className=\"max-sm:sr-only\">\n Rows per page\n </Label>\n <Select\n value={table.getState().pagination.pageSize.toString()}\n onValueChange={(value) => {\n table.setPageSize(Number(value))\n }}\n >\n <SelectTrigger id={id} className=\"w-fit whitespace-nowrap\">\n <SelectValue placeholder=\"Select number of results\" />\n </SelectTrigger>\n <SelectContent className=\"[&_*[role=option]]:ps-2 [&_*[role=option]]:pe-8 [&_*[role=option]>span]:start-auto [&_*[role=option]>span]:end-2\">\n {[5, 10, 25, 50].map((pageSize) => (\n <SelectItem key={pageSize} value={pageSize.toString()}>\n {pageSize}\n </SelectItem>\n ))}\n </SelectContent>\n </Select>\n </div>\n {/* Page number information */}\n <div className=\"flex grow justify-end text-sm whitespace-nowrap text-muted-foreground\">\n <p\n className=\"text-sm whitespace-nowrap text-muted-foreground\"\n aria-live=\"polite\"\n >\n <span className=\"text-foreground\">\n {table.getState().pagination.pageIndex *\n table.getState().pagination.pageSize +\n 1}\n -\n {Math.min(\n Math.max(\n table.getState().pagination.pageIndex *\n table.getState().pagination.pageSize +\n table.getState().pagination.pageSize,\n 0\n ),\n table.getRowCount()\n )}\n </span>{\" \"}\n of{\" \"}\n <span className=\"text-foreground\">\n {table.getRowCount().toString()}\n </span>\n </p>\n </div>\n {/* Pagination buttons */}\n <div>\n <Pagination>\n <PaginationContent>\n {/* First page button */}\n <PaginationItem>\n <Button\n size=\"icon\"\n variant=\"outline\"\n className=\"disabled:pointer-events-none disabled:opacity-50\"\n onClick={() => table.firstPage()}\n disabled={!table.getCanPreviousPage()}\n aria-label=\"Go to first page\"\n >\n <ChevronFirstIcon size={16} aria-hidden=\"true\" />\n </Button>\n </PaginationItem>\n {/* Previous page button */}\n <PaginationItem>\n <Button\n size=\"icon\"\n variant=\"outline\"\n className=\"disabled:pointer-events-none disabled:opacity-50\"\n onClick={() => table.previousPage()}\n disabled={!table.getCanPreviousPage()}\n aria-label=\"Go to previous page\"\n >\n <ChevronLeftIcon size={16} aria-hidden=\"true\" />\n </Button>\n </PaginationItem>\n {/* Next page button */}\n <PaginationItem>\n <Button\n size=\"icon\"\n variant=\"outline\"\n className=\"disabled:pointer-events-none disabled:opacity-50\"\n onClick={() => table.nextPage()}\n disabled={!table.getCanNextPage()}\n aria-label=\"Go to next page\"\n >\n <ChevronRightIcon size={16} aria-hidden=\"true\" />\n </Button>\n </PaginationItem>\n {/* Last page button */}\n <PaginationItem>\n <Button\n size=\"icon\"\n variant=\"outline\"\n className=\"disabled:pointer-events-none disabled:opacity-50\"\n onClick={() => table.lastPage()}\n disabled={!table.getCanNextPage()}\n aria-label=\"Go to last page\"\n >\n <ChevronLastIcon size={16} aria-hidden=\"true\" />\n </Button>\n </PaginationItem>\n </PaginationContent>\n </Pagination>\n </div>\n </div>\n <p className=\"mt-4 text-center text-sm text-muted-foreground\">\n Paginated table made with{\" \"}\n <a\n className=\"underline hover:text-foreground\"\n href=\"https://tanstack.com/table\"\n target=\"_blank\"\n rel=\"noopener noreferrer\"\n >\n TanStack Table\n </a>\n </p>\n </div>\n )\n}\n",
|
|
21
|
+
"type": "registry:component"
|
|
22
|
+
}
|
|
23
|
+
],
|
|
24
|
+
"meta": {
|
|
25
|
+
"tags": [
|
|
26
|
+
"table",
|
|
27
|
+
"tanstack",
|
|
28
|
+
"checkbox",
|
|
29
|
+
"sort",
|
|
30
|
+
"flag",
|
|
31
|
+
"badge",
|
|
32
|
+
"chip",
|
|
33
|
+
"pagination"
|
|
34
|
+
],
|
|
35
|
+
"colSpan": 3
|
|
36
|
+
}
|
|
37
|
+
}
|
|
@@ -0,0 +1,41 @@
|
|
|
1
|
+
{
|
|
2
|
+
"$schema": "https://ui.shadcn.com/schema/registry-item.json",
|
|
3
|
+
"name": "comp-484",
|
|
4
|
+
"type": "registry:component",
|
|
5
|
+
"dependencies": [
|
|
6
|
+
"@tanstack/react-table"
|
|
7
|
+
],
|
|
8
|
+
"registryDependencies": [
|
|
9
|
+
"https://loveui.dev/building-blocks/r/badge.json",
|
|
10
|
+
"https://loveui.dev/building-blocks/r/button.json",
|
|
11
|
+
"https://loveui.dev/building-blocks/r/checkbox.json",
|
|
12
|
+
"https://loveui.dev/building-blocks/r/pagination.json",
|
|
13
|
+
"https://loveui.dev/building-blocks/r/select.json",
|
|
14
|
+
"https://loveui.dev/building-blocks/r/table.json"
|
|
15
|
+
],
|
|
16
|
+
"files": [
|
|
17
|
+
{
|
|
18
|
+
"path": "registry/default/components/comp-484.tsx",
|
|
19
|
+
"content": "\"use client\"\n\nimport { useEffect, useState } from \"react\"\nimport {\n ColumnDef,\n flexRender,\n getCoreRowModel,\n getPaginationRowModel,\n getSortedRowModel,\n PaginationState,\n SortingState,\n useReactTable,\n} from \"@tanstack/react-table\"\nimport {\n ChevronDownIcon,\n ChevronLeftIcon,\n ChevronRightIcon,\n ChevronUpIcon,\n} from \"lucide-react\"\n\nimport { usePagination } from \"@/registry/building-blocks/default/hooks/use-pagination\"\nimport { cn } from \"@/registry/building-blocks/default/lib/utils\"\nimport { Badge } from \"@/registry/building-blocks/default/ui/badge\"\nimport { Button } from \"@/registry/building-blocks/default/ui/button\"\nimport { Checkbox } from \"@/registry/building-blocks/default/ui/checkbox\"\nimport {\n Pagination,\n PaginationContent,\n PaginationEllipsis,\n PaginationItem,\n} from \"@/registry/building-blocks/default/ui/pagination\"\nimport {\n Select,\n SelectContent,\n SelectItem,\n SelectTrigger,\n SelectValue,\n} from \"@/registry/building-blocks/default/ui/select\"\nimport {\n Table,\n TableBody,\n TableCell,\n TableHead,\n TableHeader,\n TableRow,\n} from \"@/registry/building-blocks/default/ui/table\"\n\ntype Item = {\n id: string\n name: string\n email: string\n location: string\n flag: string\n status: \"Active\" | \"Inactive\" | \"Pending\"\n balance: number\n}\n\nconst columns: ColumnDef<Item>[] = [\n {\n id: \"select\",\n header: ({ table }) => (\n <Checkbox\n checked={\n table.getIsAllPageRowsSelected() ||\n (table.getIsSomePageRowsSelected() && \"indeterminate\")\n }\n onCheckedChange={(value) => table.toggleAllPageRowsSelected(!!value)}\n aria-label=\"Select all rows\"\n />\n ),\n cell: ({ row }) => (\n <Checkbox\n checked={row.getIsSelected()}\n onCheckedChange={(value) => row.toggleSelected(!!value)}\n aria-label=\"Select row\"\n />\n ),\n size: 28,\n enableSorting: false,\n },\n {\n header: \"Name\",\n accessorKey: \"name\",\n cell: ({ row }) => (\n <div className=\"font-medium\">{row.getValue(\"name\")}</div>\n ),\n size: 180,\n },\n {\n header: \"Email\",\n accessorKey: \"email\",\n size: 200,\n },\n {\n header: \"Location\",\n accessorKey: \"location\",\n cell: ({ row }) => (\n <div>\n <span className=\"text-lg leading-none\">{row.original.flag}</span>{\" \"}\n {row.getValue(\"location\")}\n </div>\n ),\n size: 180,\n },\n {\n header: \"Status\",\n accessorKey: \"status\",\n cell: ({ row }) => (\n <Badge\n className={cn(\n row.getValue(\"status\") === \"Inactive\" &&\n \"bg-muted-foreground/60 text-primary-foreground\"\n )}\n >\n {row.getValue(\"status\")}\n </Badge>\n ),\n size: 120,\n },\n {\n header: \"Balance\",\n accessorKey: \"balance\",\n cell: ({ row }) => {\n const amount = parseFloat(row.getValue(\"balance\"))\n const formatted = new Intl.NumberFormat(\"en-US\", {\n style: \"currency\",\n currency: \"USD\",\n }).format(amount)\n return formatted\n },\n size: 120,\n },\n]\n\nexport default function Component() {\n const pageSize = 5\n\n const [pagination, setPagination] = useState<PaginationState>({\n pageIndex: 0,\n pageSize: pageSize,\n })\n\n const [sorting, setSorting] = useState<SortingState>([\n {\n id: \"name\",\n desc: false,\n },\n ])\n\n const [data, setData] = useState<Item[]>([])\n useEffect(() => {\n async function fetchPosts() {\n const res = await fetch(\n \"https://raw.githubusercontent.com/origin-space/origin-images/refs/heads/main/users-01_fertyx.json\"\n )\n const data = await res.json()\n setData(data)\n }\n fetchPosts()\n }, [])\n\n const table = useReactTable({\n data,\n columns,\n getCoreRowModel: getCoreRowModel(),\n getSortedRowModel: getSortedRowModel(),\n onSortingChange: setSorting,\n enableSortingRemoval: false,\n getPaginationRowModel: getPaginationRowModel(),\n onPaginationChange: setPagination,\n state: {\n sorting,\n pagination,\n },\n })\n\n const { pages, showLeftEllipsis, showRightEllipsis } = usePagination({\n currentPage: table.getState().pagination.pageIndex + 1,\n totalPages: table.getPageCount(),\n paginationItemsToDisplay: 5,\n })\n\n return (\n <div className=\"space-y-4\">\n <div className=\"overflow-hidden rounded-md border bg-background\">\n <Table className=\"table-fixed\">\n <TableHeader>\n {table.getHeaderGroups().map((headerGroup) => (\n <TableRow key={headerGroup.id} className=\"hover:bg-transparent\">\n {headerGroup.headers.map((header) => {\n return (\n <TableHead\n key={header.id}\n style={{ width: `${header.getSize()}px` }}\n className=\"h-11\"\n >\n {header.isPlaceholder ? null : header.column.getCanSort() ? (\n <div\n className={cn(\n header.column.getCanSort() &&\n \"flex h-full cursor-pointer items-center justify-between gap-2 select-none\"\n )}\n onClick={header.column.getToggleSortingHandler()}\n onKeyDown={(e) => {\n // Enhanced keyboard handling for sorting\n if (\n header.column.getCanSort() &&\n (e.key === \"Enter\" || e.key === \" \")\n ) {\n e.preventDefault()\n header.column.getToggleSortingHandler()?.(e)\n }\n }}\n tabIndex={header.column.getCanSort() ? 0 : undefined}\n >\n {flexRender(\n header.column.columnDef.header,\n header.getContext()\n )}\n {{\n asc: (\n <ChevronUpIcon\n className=\"shrink-0 opacity-60\"\n size={16}\n aria-hidden=\"true\"\n />\n ),\n desc: (\n <ChevronDownIcon\n className=\"shrink-0 opacity-60\"\n size={16}\n aria-hidden=\"true\"\n />\n ),\n }[header.column.getIsSorted() as string] ?? null}\n </div>\n ) : (\n flexRender(\n header.column.columnDef.header,\n header.getContext()\n )\n )}\n </TableHead>\n )\n })}\n </TableRow>\n ))}\n </TableHeader>\n <TableBody>\n {table.getRowModel().rows?.length ? (\n table.getRowModel().rows.map((row) => (\n <TableRow\n key={row.id}\n data-state={row.getIsSelected() && \"selected\"}\n >\n {row.getVisibleCells().map((cell) => (\n <TableCell key={cell.id}>\n {flexRender(\n cell.column.columnDef.cell,\n cell.getContext()\n )}\n </TableCell>\n ))}\n </TableRow>\n ))\n ) : (\n <TableRow>\n <TableCell\n colSpan={columns.length}\n className=\"h-24 text-center\"\n >\n No results.\n </TableCell>\n </TableRow>\n )}\n </TableBody>\n </Table>\n </div>\n\n {/* Pagination */}\n <div className=\"flex items-center justify-between gap-3 max-sm:flex-col\">\n {/* Page number information */}\n <p\n className=\"flex-1 text-sm whitespace-nowrap text-muted-foreground\"\n aria-live=\"polite\"\n >\n Page{\" \"}\n <span className=\"text-foreground\">\n {table.getState().pagination.pageIndex + 1}\n </span>{\" \"}\n of <span className=\"text-foreground\">{table.getPageCount()}</span>\n </p>\n\n {/* Pagination buttons */}\n <div className=\"grow\">\n <Pagination>\n <PaginationContent>\n {/* Previous page button */}\n <PaginationItem>\n <Button\n size=\"icon\"\n variant=\"outline\"\n className=\"disabled:pointer-events-none disabled:opacity-50\"\n onClick={() => table.previousPage()}\n disabled={!table.getCanPreviousPage()}\n aria-label=\"Go to previous page\"\n >\n <ChevronLeftIcon size={16} aria-hidden=\"true\" />\n </Button>\n </PaginationItem>\n\n {/* Left ellipsis (...) */}\n {showLeftEllipsis && (\n <PaginationItem>\n <PaginationEllipsis />\n </PaginationItem>\n )}\n\n {/* Page number buttons */}\n {pages.map((page) => {\n const isActive =\n page === table.getState().pagination.pageIndex + 1\n return (\n <PaginationItem key={page}>\n <Button\n size=\"icon\"\n variant={`${isActive ? \"outline\" : \"ghost\"}`}\n onClick={() => table.setPageIndex(page - 1)}\n aria-current={isActive ? \"page\" : undefined}\n >\n {page}\n </Button>\n </PaginationItem>\n )\n })}\n\n {/* Right ellipsis (...) */}\n {showRightEllipsis && (\n <PaginationItem>\n <PaginationEllipsis />\n </PaginationItem>\n )}\n\n {/* Next page button */}\n <PaginationItem>\n <Button\n size=\"icon\"\n variant=\"outline\"\n className=\"disabled:pointer-events-none disabled:opacity-50\"\n onClick={() => table.nextPage()}\n disabled={!table.getCanNextPage()}\n aria-label=\"Go to next page\"\n >\n <ChevronRightIcon size={16} aria-hidden=\"true\" />\n </Button>\n </PaginationItem>\n </PaginationContent>\n </Pagination>\n </div>\n\n {/* Results per page */}\n <div className=\"flex flex-1 justify-end\">\n <Select\n value={table.getState().pagination.pageSize.toString()}\n onValueChange={(value) => {\n table.setPageSize(Number(value))\n }}\n aria-label=\"Results per page\"\n >\n <SelectTrigger\n id=\"results-per-page\"\n className=\"w-fit whitespace-nowrap\"\n >\n <SelectValue placeholder=\"Select number of results\" />\n </SelectTrigger>\n <SelectContent>\n {[5, 10, 25, 50].map((pageSize) => (\n <SelectItem key={pageSize} value={pageSize.toString()}>\n {pageSize} / page\n </SelectItem>\n ))}\n </SelectContent>\n </Select>\n </div>\n </div>\n <p className=\"mt-4 text-center text-sm text-muted-foreground\">\n Numeric pagination made with{\" \"}\n <a\n className=\"underline hover:text-foreground\"\n href=\"https://tanstack.com/table\"\n target=\"_blank\"\n rel=\"noopener noreferrer\"\n >\n TanStack Table\n </a>\n </p>\n </div>\n )\n}\n",
|
|
20
|
+
"type": "registry:component"
|
|
21
|
+
},
|
|
22
|
+
{
|
|
23
|
+
"path": "registry/default/hooks/use-pagination.ts",
|
|
24
|
+
"content": "type UsePaginationProps = {\n currentPage: number\n totalPages: number\n paginationItemsToDisplay: number\n}\n\ntype UsePaginationReturn = {\n pages: number[]\n showLeftEllipsis: boolean\n showRightEllipsis: boolean\n}\n\nexport function usePagination({\n currentPage,\n totalPages,\n paginationItemsToDisplay,\n}: UsePaginationProps): UsePaginationReturn {\n const showLeftEllipsis = currentPage - 1 > paginationItemsToDisplay / 2\n const showRightEllipsis =\n totalPages - currentPage + 1 > paginationItemsToDisplay / 2\n\n function calculatePaginationRange(): number[] {\n if (totalPages <= paginationItemsToDisplay) {\n return Array.from({ length: totalPages }, (_, i) => i + 1)\n }\n\n const halfDisplay = Math.floor(paginationItemsToDisplay / 2)\n const initialRange = {\n start: currentPage - halfDisplay,\n end: currentPage + halfDisplay,\n }\n\n const adjustedRange = {\n start: Math.max(1, initialRange.start),\n end: Math.min(totalPages, initialRange.end),\n }\n\n if (adjustedRange.start === 1) {\n adjustedRange.end = paginationItemsToDisplay\n }\n if (adjustedRange.end === totalPages) {\n adjustedRange.start = totalPages - paginationItemsToDisplay + 1\n }\n\n if (showLeftEllipsis) adjustedRange.start++\n if (showRightEllipsis) adjustedRange.end--\n\n return Array.from(\n { length: adjustedRange.end - adjustedRange.start + 1 },\n (_, i) => adjustedRange.start + i\n )\n }\n\n const pages = calculatePaginationRange()\n\n return {\n pages,\n showLeftEllipsis,\n showRightEllipsis,\n }\n}\n",
|
|
25
|
+
"type": "registry:hook"
|
|
26
|
+
}
|
|
27
|
+
],
|
|
28
|
+
"meta": {
|
|
29
|
+
"tags": [
|
|
30
|
+
"table",
|
|
31
|
+
"tanstack",
|
|
32
|
+
"checkbox",
|
|
33
|
+
"sort",
|
|
34
|
+
"flag",
|
|
35
|
+
"badge",
|
|
36
|
+
"chip",
|
|
37
|
+
"pagination"
|
|
38
|
+
],
|
|
39
|
+
"colSpan": 3
|
|
40
|
+
}
|
|
41
|
+
}
|
|
@@ -0,0 +1,43 @@
|
|
|
1
|
+
{
|
|
2
|
+
"$schema": "https://ui.shadcn.com/schema/registry-item.json",
|
|
3
|
+
"name": "comp-485",
|
|
4
|
+
"type": "registry:component",
|
|
5
|
+
"dependencies": [
|
|
6
|
+
"@tanstack/react-table"
|
|
7
|
+
],
|
|
8
|
+
"registryDependencies": [
|
|
9
|
+
"https://loveui.dev/building-blocks/r/alert-dialog.json",
|
|
10
|
+
"https://loveui.dev/building-blocks/r/badge.json",
|
|
11
|
+
"https://loveui.dev/building-blocks/r/button.json",
|
|
12
|
+
"https://loveui.dev/building-blocks/r/checkbox.json",
|
|
13
|
+
"https://loveui.dev/building-blocks/r/dropdown-menu.json",
|
|
14
|
+
"https://loveui.dev/building-blocks/r/input.json",
|
|
15
|
+
"https://loveui.dev/building-blocks/r/label.json",
|
|
16
|
+
"https://loveui.dev/building-blocks/r/pagination.json",
|
|
17
|
+
"https://loveui.dev/building-blocks/r/popover.json",
|
|
18
|
+
"https://loveui.dev/building-blocks/r/select.json",
|
|
19
|
+
"https://loveui.dev/building-blocks/r/table.json"
|
|
20
|
+
],
|
|
21
|
+
"files": [
|
|
22
|
+
{
|
|
23
|
+
"path": "registry/default/components/comp-485.tsx",
|
|
24
|
+
"content": "\"use client\"\n\nimport { useEffect, useId, useMemo, useRef, useState } from \"react\"\nimport {\n ColumnDef,\n ColumnFiltersState,\n FilterFn,\n flexRender,\n getCoreRowModel,\n getFacetedUniqueValues,\n getFilteredRowModel,\n getPaginationRowModel,\n getSortedRowModel,\n PaginationState,\n Row,\n SortingState,\n useReactTable,\n VisibilityState,\n} from \"@tanstack/react-table\"\nimport {\n ChevronDownIcon,\n ChevronFirstIcon,\n ChevronLastIcon,\n ChevronLeftIcon,\n ChevronRightIcon,\n ChevronUpIcon,\n CircleAlertIcon,\n CircleXIcon,\n Columns3Icon,\n EllipsisIcon,\n FilterIcon,\n ListFilterIcon,\n PlusIcon,\n TrashIcon,\n} from \"lucide-react\"\n\nimport { cn } from \"@/registry/building-blocks/default/lib/utils\"\nimport {\n AlertDialog,\n AlertDialogAction,\n AlertDialogCancel,\n AlertDialogContent,\n AlertDialogDescription,\n AlertDialogFooter,\n AlertDialogHeader,\n AlertDialogTitle,\n AlertDialogTrigger,\n} from \"@/registry/building-blocks/default/ui/alert-dialog\"\nimport { Badge } from \"@/registry/building-blocks/default/ui/badge\"\nimport { Button } from \"@/registry/building-blocks/default/ui/button\"\nimport { Checkbox } from \"@/registry/building-blocks/default/ui/checkbox\"\nimport {\n DropdownMenu,\n DropdownMenuCheckboxItem,\n DropdownMenuContent,\n DropdownMenuGroup,\n DropdownMenuItem,\n DropdownMenuLabel,\n DropdownMenuPortal,\n DropdownMenuSeparator,\n DropdownMenuShortcut,\n DropdownMenuSub,\n DropdownMenuSubContent,\n DropdownMenuSubTrigger,\n DropdownMenuTrigger,\n} from \"@/registry/building-blocks/default/ui/dropdown-menu\"\nimport { Input } from \"@/registry/building-blocks/default/ui/input\"\nimport { Label } from \"@/registry/building-blocks/default/ui/label\"\nimport {\n Pagination,\n PaginationContent,\n PaginationItem,\n} from \"@/registry/building-blocks/default/ui/pagination\"\nimport {\n Popover,\n PopoverContent,\n PopoverTrigger,\n} from \"@/registry/building-blocks/default/ui/popover\"\nimport {\n Select,\n SelectContent,\n SelectItem,\n SelectTrigger,\n SelectValue,\n} from \"@/registry/building-blocks/default/ui/select\"\nimport {\n Table,\n TableBody,\n TableCell,\n TableHead,\n TableHeader,\n TableRow,\n} from \"@/registry/building-blocks/default/ui/table\"\n\ntype Item = {\n id: string\n name: string\n email: string\n location: string\n flag: string\n status: \"Active\" | \"Inactive\" | \"Pending\"\n balance: number\n}\n\n// Custom filter function for multi-column searching\nconst multiColumnFilterFn: FilterFn<Item> = (row, columnId, filterValue) => {\n const searchableRowContent =\n `${row.original.name} ${row.original.email}`.toLowerCase()\n const searchTerm = (filterValue ?? \"\").toLowerCase()\n return searchableRowContent.includes(searchTerm)\n}\n\nconst statusFilterFn: FilterFn<Item> = (\n row,\n columnId,\n filterValue: string[]\n) => {\n if (!filterValue?.length) return true\n const status = row.getValue(columnId) as string\n return filterValue.includes(status)\n}\n\nconst columns: ColumnDef<Item>[] = [\n {\n id: \"select\",\n header: ({ table }) => (\n <Checkbox\n checked={\n table.getIsAllPageRowsSelected() ||\n (table.getIsSomePageRowsSelected() && \"indeterminate\")\n }\n onCheckedChange={(value) => table.toggleAllPageRowsSelected(!!value)}\n aria-label=\"Select all\"\n />\n ),\n cell: ({ row }) => (\n <Checkbox\n checked={row.getIsSelected()}\n onCheckedChange={(value) => row.toggleSelected(!!value)}\n aria-label=\"Select row\"\n />\n ),\n size: 28,\n enableSorting: false,\n enableHiding: false,\n },\n {\n header: \"Name\",\n accessorKey: \"name\",\n cell: ({ row }) => (\n <div className=\"font-medium\">{row.getValue(\"name\")}</div>\n ),\n size: 180,\n filterFn: multiColumnFilterFn,\n enableHiding: false,\n },\n {\n header: \"Email\",\n accessorKey: \"email\",\n size: 220,\n },\n {\n header: \"Location\",\n accessorKey: \"location\",\n cell: ({ row }) => (\n <div>\n <span className=\"text-lg leading-none\">{row.original.flag}</span>{\" \"}\n {row.getValue(\"location\")}\n </div>\n ),\n size: 180,\n },\n {\n header: \"Status\",\n accessorKey: \"status\",\n cell: ({ row }) => (\n <Badge\n className={cn(\n row.getValue(\"status\") === \"Inactive\" &&\n \"bg-muted-foreground/60 text-primary-foreground\"\n )}\n >\n {row.getValue(\"status\")}\n </Badge>\n ),\n size: 100,\n filterFn: statusFilterFn,\n },\n {\n header: \"Performance\",\n accessorKey: \"performance\",\n },\n {\n header: \"Balance\",\n accessorKey: \"balance\",\n cell: ({ row }) => {\n const amount = parseFloat(row.getValue(\"balance\"))\n const formatted = new Intl.NumberFormat(\"en-US\", {\n style: \"currency\",\n currency: \"USD\",\n }).format(amount)\n return formatted\n },\n size: 120,\n },\n {\n id: \"actions\",\n header: () => <span className=\"sr-only\">Actions</span>,\n cell: ({ row }) => <RowActions row={row} />,\n size: 60,\n enableHiding: false,\n },\n]\n\nexport default function Component() {\n const id = useId()\n const [columnFilters, setColumnFilters] = useState<ColumnFiltersState>([])\n const [columnVisibility, setColumnVisibility] = useState<VisibilityState>({})\n const [pagination, setPagination] = useState<PaginationState>({\n pageIndex: 0,\n pageSize: 10,\n })\n const inputRef = useRef<HTMLInputElement>(null)\n\n const [sorting, setSorting] = useState<SortingState>([\n {\n id: \"name\",\n desc: false,\n },\n ])\n\n const [data, setData] = useState<Item[]>([])\n useEffect(() => {\n async function fetchPosts() {\n const res = await fetch(\n \"https://raw.githubusercontent.com/origin-space/origin-images/refs/heads/main/users-01_fertyx.json\"\n )\n const data = await res.json()\n setData(data)\n }\n fetchPosts()\n }, [])\n\n const handleDeleteRows = () => {\n const selectedRows = table.getSelectedRowModel().rows\n const updatedData = data.filter(\n (item) => !selectedRows.some((row) => row.original.id === item.id)\n )\n setData(updatedData)\n table.resetRowSelection()\n }\n\n const table = useReactTable({\n data,\n columns,\n getCoreRowModel: getCoreRowModel(),\n getSortedRowModel: getSortedRowModel(),\n onSortingChange: setSorting,\n enableSortingRemoval: false,\n getPaginationRowModel: getPaginationRowModel(),\n onPaginationChange: setPagination,\n onColumnFiltersChange: setColumnFilters,\n onColumnVisibilityChange: setColumnVisibility,\n getFilteredRowModel: getFilteredRowModel(),\n getFacetedUniqueValues: getFacetedUniqueValues(),\n state: {\n sorting,\n pagination,\n columnFilters,\n columnVisibility,\n },\n })\n\n // Get unique status values\n const uniqueStatusValues = useMemo(() => {\n const statusColumn = table.getColumn(\"status\")\n\n if (!statusColumn) return []\n\n const values = Array.from(statusColumn.getFacetedUniqueValues().keys())\n\n return values.sort()\n }, [table.getColumn(\"status\")?.getFacetedUniqueValues()])\n\n // Get counts for each status\n const statusCounts = useMemo(() => {\n const statusColumn = table.getColumn(\"status\")\n if (!statusColumn) return new Map()\n return statusColumn.getFacetedUniqueValues()\n }, [table.getColumn(\"status\")?.getFacetedUniqueValues()])\n\n const selectedStatuses = useMemo(() => {\n const filterValue = table.getColumn(\"status\")?.getFilterValue() as string[]\n return filterValue ?? []\n }, [table.getColumn(\"status\")?.getFilterValue()])\n\n const handleStatusChange = (checked: boolean, value: string) => {\n const filterValue = table.getColumn(\"status\")?.getFilterValue() as string[]\n const newFilterValue = filterValue ? [...filterValue] : []\n\n if (checked) {\n newFilterValue.push(value)\n } else {\n const index = newFilterValue.indexOf(value)\n if (index > -1) {\n newFilterValue.splice(index, 1)\n }\n }\n\n table\n .getColumn(\"status\")\n ?.setFilterValue(newFilterValue.length ? newFilterValue : undefined)\n }\n\n return (\n <div className=\"space-y-4\">\n {/* Filters */}\n <div className=\"flex flex-wrap items-center justify-between gap-3\">\n <div className=\"flex items-center gap-3\">\n {/* Filter by name or email */}\n <div className=\"relative\">\n <Input\n id={`${id}-input`}\n ref={inputRef}\n className={cn(\n \"peer min-w-60 ps-9\",\n Boolean(table.getColumn(\"name\")?.getFilterValue()) && \"pe-9\"\n )}\n value={\n (table.getColumn(\"name\")?.getFilterValue() ?? \"\") as string\n }\n onChange={(e) =>\n table.getColumn(\"name\")?.setFilterValue(e.target.value)\n }\n placeholder=\"Filter by name or email...\"\n type=\"text\"\n aria-label=\"Filter by name or email\"\n />\n <div className=\"pointer-events-none absolute inset-y-0 start-0 flex items-center justify-center ps-3 text-muted-foreground/80 peer-disabled:opacity-50\">\n <ListFilterIcon size={16} aria-hidden=\"true\" />\n </div>\n {Boolean(table.getColumn(\"name\")?.getFilterValue()) && (\n <button\n className=\"absolute inset-y-0 end-0 flex h-full w-9 items-center justify-center rounded-e-md text-muted-foreground/80 transition-[color,box-shadow] outline-none hover:text-foreground focus:z-10 focus-visible:border-ring focus-visible:ring-[3px] focus-visible:ring-ring/50 disabled:pointer-events-none disabled:cursor-not-allowed disabled:opacity-50\"\n aria-label=\"Clear filter\"\n onClick={() => {\n table.getColumn(\"name\")?.setFilterValue(\"\")\n if (inputRef.current) {\n inputRef.current.focus()\n }\n }}\n >\n <CircleXIcon size={16} aria-hidden=\"true\" />\n </button>\n )}\n </div>\n {/* Filter by status */}\n <Popover>\n <PopoverTrigger asChild>\n <Button variant=\"outline\">\n <FilterIcon\n className=\"-ms-1 opacity-60\"\n size={16}\n aria-hidden=\"true\"\n />\n Status\n {selectedStatuses.length > 0 && (\n <span className=\"-me-1 inline-flex h-5 max-h-full items-center rounded border bg-background px-1 font-[inherit] text-[0.625rem] font-medium text-muted-foreground/70\">\n {selectedStatuses.length}\n </span>\n )}\n </Button>\n </PopoverTrigger>\n <PopoverContent className=\"w-auto min-w-36 p-3\" align=\"start\">\n <div className=\"space-y-3\">\n <div className=\"text-xs font-medium text-muted-foreground\">\n Filters\n </div>\n <div className=\"space-y-3\">\n {uniqueStatusValues.map((value, i) => (\n <div key={value} className=\"flex items-center gap-2\">\n <Checkbox\n id={`${id}-${i}`}\n checked={selectedStatuses.includes(value)}\n onCheckedChange={(checked: boolean) =>\n handleStatusChange(checked, value)\n }\n />\n <Label\n htmlFor={`${id}-${i}`}\n className=\"flex grow justify-between gap-2 font-normal\"\n >\n {value}{\" \"}\n <span className=\"ms-2 text-xs text-muted-foreground\">\n {statusCounts.get(value)}\n </span>\n </Label>\n </div>\n ))}\n </div>\n </div>\n </PopoverContent>\n </Popover>\n {/* Toggle columns visibility */}\n <DropdownMenu>\n <DropdownMenuTrigger asChild>\n <Button variant=\"outline\">\n <Columns3Icon\n className=\"-ms-1 opacity-60\"\n size={16}\n aria-hidden=\"true\"\n />\n View\n </Button>\n </DropdownMenuTrigger>\n <DropdownMenuContent align=\"end\">\n <DropdownMenuLabel>Toggle columns</DropdownMenuLabel>\n {table\n .getAllColumns()\n .filter((column) => column.getCanHide())\n .map((column) => {\n return (\n <DropdownMenuCheckboxItem\n key={column.id}\n className=\"capitalize\"\n checked={column.getIsVisible()}\n onCheckedChange={(value) =>\n column.toggleVisibility(!!value)\n }\n onSelect={(event) => event.preventDefault()}\n >\n {column.id}\n </DropdownMenuCheckboxItem>\n )\n })}\n </DropdownMenuContent>\n </DropdownMenu>\n </div>\n <div className=\"flex items-center gap-3\">\n {/* Delete button */}\n {table.getSelectedRowModel().rows.length > 0 && (\n <AlertDialog>\n <AlertDialogTrigger asChild>\n <Button className=\"ml-auto\" variant=\"outline\">\n <TrashIcon\n className=\"-ms-1 opacity-60\"\n size={16}\n aria-hidden=\"true\"\n />\n Delete\n <span className=\"-me-1 inline-flex h-5 max-h-full items-center rounded border bg-background px-1 font-[inherit] text-[0.625rem] font-medium text-muted-foreground/70\">\n {table.getSelectedRowModel().rows.length}\n </span>\n </Button>\n </AlertDialogTrigger>\n <AlertDialogContent>\n <div className=\"flex flex-col gap-2 max-sm:items-center sm:flex-row sm:gap-4\">\n <div\n className=\"flex size-9 shrink-0 items-center justify-center rounded-full border\"\n aria-hidden=\"true\"\n >\n <CircleAlertIcon className=\"opacity-80\" size={16} />\n </div>\n <AlertDialogHeader>\n <AlertDialogTitle>\n Are you absolutely sure?\n </AlertDialogTitle>\n <AlertDialogDescription>\n This action cannot be undone. This will permanently delete{\" \"}\n {table.getSelectedRowModel().rows.length} selected{\" \"}\n {table.getSelectedRowModel().rows.length === 1\n ? \"row\"\n : \"rows\"}\n .\n </AlertDialogDescription>\n </AlertDialogHeader>\n </div>\n <AlertDialogFooter>\n <AlertDialogCancel>Cancel</AlertDialogCancel>\n <AlertDialogAction onClick={handleDeleteRows}>\n Delete\n </AlertDialogAction>\n </AlertDialogFooter>\n </AlertDialogContent>\n </AlertDialog>\n )}\n {/* Add user button */}\n <Button className=\"ml-auto\" variant=\"outline\">\n <PlusIcon\n className=\"-ms-1 opacity-60\"\n size={16}\n aria-hidden=\"true\"\n />\n Add user\n </Button>\n </div>\n </div>\n\n {/* Table */}\n <div className=\"overflow-hidden rounded-md border bg-background\">\n <Table className=\"table-fixed\">\n <TableHeader>\n {table.getHeaderGroups().map((headerGroup) => (\n <TableRow key={headerGroup.id} className=\"hover:bg-transparent\">\n {headerGroup.headers.map((header) => {\n return (\n <TableHead\n key={header.id}\n style={{ width: `${header.getSize()}px` }}\n className=\"h-11\"\n >\n {header.isPlaceholder ? null : header.column.getCanSort() ? (\n <div\n className={cn(\n header.column.getCanSort() &&\n \"flex h-full cursor-pointer items-center justify-between gap-2 select-none\"\n )}\n onClick={header.column.getToggleSortingHandler()}\n onKeyDown={(e) => {\n // Enhanced keyboard handling for sorting\n if (\n header.column.getCanSort() &&\n (e.key === \"Enter\" || e.key === \" \")\n ) {\n e.preventDefault()\n header.column.getToggleSortingHandler()?.(e)\n }\n }}\n tabIndex={header.column.getCanSort() ? 0 : undefined}\n >\n {flexRender(\n header.column.columnDef.header,\n header.getContext()\n )}\n {{\n asc: (\n <ChevronUpIcon\n className=\"shrink-0 opacity-60\"\n size={16}\n aria-hidden=\"true\"\n />\n ),\n desc: (\n <ChevronDownIcon\n className=\"shrink-0 opacity-60\"\n size={16}\n aria-hidden=\"true\"\n />\n ),\n }[header.column.getIsSorted() as string] ?? null}\n </div>\n ) : (\n flexRender(\n header.column.columnDef.header,\n header.getContext()\n )\n )}\n </TableHead>\n )\n })}\n </TableRow>\n ))}\n </TableHeader>\n <TableBody>\n {table.getRowModel().rows?.length ? (\n table.getRowModel().rows.map((row) => (\n <TableRow\n key={row.id}\n data-state={row.getIsSelected() && \"selected\"}\n >\n {row.getVisibleCells().map((cell) => (\n <TableCell key={cell.id} className=\"last:py-0\">\n {flexRender(\n cell.column.columnDef.cell,\n cell.getContext()\n )}\n </TableCell>\n ))}\n </TableRow>\n ))\n ) : (\n <TableRow>\n <TableCell\n colSpan={columns.length}\n className=\"h-24 text-center\"\n >\n No results.\n </TableCell>\n </TableRow>\n )}\n </TableBody>\n </Table>\n </div>\n\n {/* Pagination */}\n <div className=\"flex items-center justify-between gap-8\">\n {/* Results per page */}\n <div className=\"flex items-center gap-3\">\n <Label htmlFor={id} className=\"max-sm:sr-only\">\n Rows per page\n </Label>\n <Select\n value={table.getState().pagination.pageSize.toString()}\n onValueChange={(value) => {\n table.setPageSize(Number(value))\n }}\n >\n <SelectTrigger id={id} className=\"w-fit whitespace-nowrap\">\n <SelectValue placeholder=\"Select number of results\" />\n </SelectTrigger>\n <SelectContent className=\"[&_*[role=option]]:ps-2 [&_*[role=option]]:pe-8 [&_*[role=option]>span]:start-auto [&_*[role=option]>span]:end-2\">\n {[5, 10, 25, 50].map((pageSize) => (\n <SelectItem key={pageSize} value={pageSize.toString()}>\n {pageSize}\n </SelectItem>\n ))}\n </SelectContent>\n </Select>\n </div>\n {/* Page number information */}\n <div className=\"flex grow justify-end text-sm whitespace-nowrap text-muted-foreground\">\n <p\n className=\"text-sm whitespace-nowrap text-muted-foreground\"\n aria-live=\"polite\"\n >\n <span className=\"text-foreground\">\n {table.getState().pagination.pageIndex *\n table.getState().pagination.pageSize +\n 1}\n -\n {Math.min(\n Math.max(\n table.getState().pagination.pageIndex *\n table.getState().pagination.pageSize +\n table.getState().pagination.pageSize,\n 0\n ),\n table.getRowCount()\n )}\n </span>{\" \"}\n of{\" \"}\n <span className=\"text-foreground\">\n {table.getRowCount().toString()}\n </span>\n </p>\n </div>\n\n {/* Pagination buttons */}\n <div>\n <Pagination>\n <PaginationContent>\n {/* First page button */}\n <PaginationItem>\n <Button\n size=\"icon\"\n variant=\"outline\"\n className=\"disabled:pointer-events-none disabled:opacity-50\"\n onClick={() => table.firstPage()}\n disabled={!table.getCanPreviousPage()}\n aria-label=\"Go to first page\"\n >\n <ChevronFirstIcon size={16} aria-hidden=\"true\" />\n </Button>\n </PaginationItem>\n {/* Previous page button */}\n <PaginationItem>\n <Button\n size=\"icon\"\n variant=\"outline\"\n className=\"disabled:pointer-events-none disabled:opacity-50\"\n onClick={() => table.previousPage()}\n disabled={!table.getCanPreviousPage()}\n aria-label=\"Go to previous page\"\n >\n <ChevronLeftIcon size={16} aria-hidden=\"true\" />\n </Button>\n </PaginationItem>\n {/* Next page button */}\n <PaginationItem>\n <Button\n size=\"icon\"\n variant=\"outline\"\n className=\"disabled:pointer-events-none disabled:opacity-50\"\n onClick={() => table.nextPage()}\n disabled={!table.getCanNextPage()}\n aria-label=\"Go to next page\"\n >\n <ChevronRightIcon size={16} aria-hidden=\"true\" />\n </Button>\n </PaginationItem>\n {/* Last page button */}\n <PaginationItem>\n <Button\n size=\"icon\"\n variant=\"outline\"\n className=\"disabled:pointer-events-none disabled:opacity-50\"\n onClick={() => table.lastPage()}\n disabled={!table.getCanNextPage()}\n aria-label=\"Go to last page\"\n >\n <ChevronLastIcon size={16} aria-hidden=\"true\" />\n </Button>\n </PaginationItem>\n </PaginationContent>\n </Pagination>\n </div>\n </div>\n <p className=\"mt-4 text-center text-sm text-muted-foreground\">\n Example of a more complex table made with{\" \"}\n <a\n className=\"underline hover:text-foreground\"\n href=\"https://tanstack.com/table\"\n target=\"_blank\"\n rel=\"noopener noreferrer\"\n >\n TanStack Table\n </a>\n </p>\n </div>\n )\n}\n\nfunction RowActions({ row }: { row: Row<Item> }) {\n return (\n <DropdownMenu>\n <DropdownMenuTrigger asChild>\n <div className=\"flex justify-end\">\n <Button\n size=\"icon\"\n variant=\"ghost\"\n className=\"shadow-none\"\n aria-label=\"Edit item\"\n >\n <EllipsisIcon size={16} aria-hidden=\"true\" />\n </Button>\n </div>\n </DropdownMenuTrigger>\n <DropdownMenuContent align=\"end\">\n <DropdownMenuGroup>\n <DropdownMenuItem>\n <span>Edit</span>\n <DropdownMenuShortcut>⌘E</DropdownMenuShortcut>\n </DropdownMenuItem>\n <DropdownMenuItem>\n <span>Duplicate</span>\n <DropdownMenuShortcut>⌘D</DropdownMenuShortcut>\n </DropdownMenuItem>\n </DropdownMenuGroup>\n <DropdownMenuSeparator />\n <DropdownMenuGroup>\n <DropdownMenuItem>\n <span>Archive</span>\n <DropdownMenuShortcut>⌘A</DropdownMenuShortcut>\n </DropdownMenuItem>\n <DropdownMenuSub>\n <DropdownMenuSubTrigger>More</DropdownMenuSubTrigger>\n <DropdownMenuPortal>\n <DropdownMenuSubContent>\n <DropdownMenuItem>Move to project</DropdownMenuItem>\n <DropdownMenuItem>Move to folder</DropdownMenuItem>\n <DropdownMenuSeparator />\n <DropdownMenuItem>Advanced options</DropdownMenuItem>\n </DropdownMenuSubContent>\n </DropdownMenuPortal>\n </DropdownMenuSub>\n </DropdownMenuGroup>\n <DropdownMenuSeparator />\n <DropdownMenuGroup>\n <DropdownMenuItem>Share</DropdownMenuItem>\n <DropdownMenuItem>Add to favorites</DropdownMenuItem>\n </DropdownMenuGroup>\n <DropdownMenuSeparator />\n <DropdownMenuItem className=\"text-destructive focus:text-destructive\">\n <span>Delete</span>\n <DropdownMenuShortcut>⌘⌫</DropdownMenuShortcut>\n </DropdownMenuItem>\n </DropdownMenuContent>\n </DropdownMenu>\n )\n}\n",
|
|
25
|
+
"type": "registry:component"
|
|
26
|
+
}
|
|
27
|
+
],
|
|
28
|
+
"meta": {
|
|
29
|
+
"tags": [
|
|
30
|
+
"table",
|
|
31
|
+
"tanstack",
|
|
32
|
+
"checkbox",
|
|
33
|
+
"sort",
|
|
34
|
+
"flag",
|
|
35
|
+
"badge",
|
|
36
|
+
"chip",
|
|
37
|
+
"pagination",
|
|
38
|
+
"filter",
|
|
39
|
+
"select"
|
|
40
|
+
],
|
|
41
|
+
"colSpan": 3
|
|
42
|
+
}
|
|
43
|
+
}
|