@agroshine/ags-web-ui-kit 1.1.0 → 1.2.0

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
package/LICENSE ADDED
@@ -0,0 +1,21 @@
1
+ MIT License
2
+
3
+ Copyright (c) 2026 AgroShine
4
+
5
+ Permission is hereby granted, free of charge, to any person obtaining a copy
6
+ of this software and associated documentation files (the "Software"), to deal
7
+ in the Software without restriction, including without limitation the rights
8
+ to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
9
+ copies of the Software, and to permit persons to whom the Software is
10
+ furnished to do so, subject to the following conditions:
11
+
12
+ The above copyright notice and this permission notice shall be included in all
13
+ copies or substantial portions of the Software.
14
+
15
+ THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
16
+ IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
17
+ FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
18
+ AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
19
+ LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
20
+ OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
21
+ SOFTWARE.
package/README.md CHANGED
@@ -1,17 +1,29 @@
1
- # ags-web-ui-kit
1
+ # @agroshine/ags-web-ui-kit
2
2
 
3
3
  Librería de componentes React para AgroShine · Luna Nueva.
4
4
 
5
5
  Stack: React 18+ · TypeScript · Tailwind CSS v4 · shadcn/ui · Radix UI · class-variance-authority · lucide-react.
6
6
 
7
- ## Instalación (workspace pnpm)
7
+ ## Instalación
8
+
9
+ Desde el registro público de npm:
10
+
11
+ ```bash
12
+ pnpm add @agroshine/ags-web-ui-kit
13
+ # o
14
+ npm i @agroshine/ags-web-ui-kit
15
+ # o
16
+ yarn add @agroshine/ags-web-ui-kit
17
+ ```
18
+
19
+ ### Workspace pnpm (consumidores internos)
8
20
 
9
21
  Desde un consumidor del workspace (admin, client, website):
10
22
 
11
23
  ```jsonc
12
24
  // package.json
13
25
  "dependencies": {
14
- "ags-web-ui-kit": "workspace:*"
26
+ "@agroshine/ags-web-ui-kit": "workspace:*"
15
27
  }
16
28
  ```
17
29
 
@@ -19,7 +31,7 @@ Luego:
19
31
 
20
32
  ```bash
21
33
  pnpm install
22
- pnpm --filter ags-web-ui-kit build
34
+ pnpm --filter @agroshine/ags-web-ui-kit build
23
35
  ```
24
36
 
25
37
  ## Uso del Tailwind preset
@@ -27,10 +39,10 @@ pnpm --filter ags-web-ui-kit build
27
39
  ```js
28
40
  // tailwind.config.{js,ts}
29
41
  module.exports = {
30
- presets: [require('ags-web-ui-kit/tailwind.preset')],
42
+ presets: [require('@agroshine/ags-web-ui-kit/tailwind.preset')],
31
43
  content: [
32
44
  './src/**/*.{ts,tsx}',
33
- './node_modules/ags-web-ui-kit/dist/**/*.{js,cjs}',
45
+ './node_modules/@agroshine/ags-web-ui-kit/dist/**/*.{js,cjs}',
34
46
  ],
35
47
  };
36
48
  ```
@@ -40,16 +52,16 @@ En Tailwind v4 (config CSS-first), importar también los tokens semánticos:
40
52
  ```css
41
53
  /* src/index.css */
42
54
  @import 'tailwindcss';
43
- @import 'ags-web-ui-kit/styles/tokens.css';
55
+ @import '@agroshine/ags-web-ui-kit/styles/tokens.css';
44
56
  ```
45
57
 
46
58
  ## Imports
47
59
 
48
60
  ```ts
49
- import { Button, Tag, Drawer } from 'ags-web-ui-kit';
61
+ import { Button, Tag, Drawer } from '@agroshine/ags-web-ui-kit';
50
62
  // o por categoría:
51
- import { Button } from 'ags-web-ui-kit/atoms';
52
- import { Sheet } from 'ags-web-ui-kit/ui';
63
+ import { Button } from '@agroshine/ags-web-ui-kit/atoms';
64
+ import { Sheet } from '@agroshine/ags-web-ui-kit/ui';
53
65
  ```
54
66
 
55
67
  ## Estructura
@@ -1,14 +1,14 @@
1
1
  import { FormItem } from './chunk-QEG27NX6.js';
2
2
  import { Spinner, Button } from './chunk-QAZMI5VH.js';
3
3
  import { Accordion, Calendar as Calendar$1, AccordionItem, AccordionTrigger, AccordionContent } from './chunk-6O2IDBTX.js';
4
- import { Popover, PopoverTrigger, PopoverContent } from './chunk-6YUNWKT3.js';
4
+ import { Popover, PopoverTrigger, PopoverContent, PopoverAnchor } from './chunk-6YUNWKT3.js';
5
5
  import { cn } from './chunk-MOED3QPY.js';
6
- import React, { forwardRef, useState, useCallback, useMemo, useRef, useEffect } from 'react';
6
+ import React, { forwardRef, useState, useCallback, useMemo, useRef } from 'react';
7
7
  import { jsx, jsxs, Fragment } from 'react/jsx-runtime';
8
8
  import clsx from 'clsx';
9
9
  import { cva } from 'class-variance-authority';
10
- import { Search, Calendar, ServerCrash, FileQuestion, Info, AlertTriangle, XCircle, CheckCircle2, ChevronRight } from 'lucide-react';
11
- import { faArrowLeft, faSearch } from '@fortawesome/free-solid-svg-icons';
10
+ import { Search, Calendar, ChevronDown, X, ServerCrash, FileQuestion, Info, AlertTriangle, XCircle, CheckCircle2, ChevronRight, ArrowUpRight } from 'lucide-react';
11
+ import { faArrowLeft } from '@fortawesome/free-solid-svg-icons';
12
12
  import { FontAwesomeIcon } from '@fortawesome/react-fontawesome';
13
13
  import dayjs from 'dayjs';
14
14
  import { Toaster as Toaster$1 } from 'sonner';
@@ -713,114 +713,249 @@ var QueryState = forwardRef(function QueryState2({
713
713
  return /* @__PURE__ */ jsx(Fragment, { children });
714
714
  });
715
715
  QueryState.displayName = "QueryState";
716
- function SearchFilterBar({
716
+ var SearchCategoryMenu = ({
717
717
  options,
718
- selectedOption,
719
- onOptionChange,
720
- searchValue,
721
- onSearchChange,
722
- searchPlaceholder = "Buscar...",
723
- className = ""
724
- }) {
725
- const [isOpen, setIsOpen] = useState(false);
726
- const dropdownRef = useRef(null);
727
- const selectedLabel = useMemo(
728
- () => options.find((option) => String(option.value) === selectedOption)?.label ?? selectedOption,
729
- [options, selectedOption]
730
- );
731
- useEffect(() => {
732
- const onClickOutside = (event) => {
733
- if (!dropdownRef.current) return;
734
- if (!dropdownRef.current.contains(event.target)) {
735
- setIsOpen(false);
736
- }
737
- };
738
- document.addEventListener("mousedown", onClickOutside);
739
- return () => document.removeEventListener("mousedown", onClickOutside);
740
- }, []);
718
+ isActive,
719
+ onSelect,
720
+ multi
721
+ }) => /* @__PURE__ */ jsx(Fragment, { children: options.map((opt) => {
722
+ const v = String(opt.value);
723
+ const active = isActive(v);
741
724
  return /* @__PURE__ */ jsxs(
742
- "div",
725
+ "button",
743
726
  {
744
- className: `flex w-full flex-col gap-3 sm:flex-row sm:items-stretch sm:gap-0 ${className}`,
727
+ type: "button",
728
+ onClick: () => onSelect(v),
729
+ disabled: opt.disabled,
730
+ className: cn(
731
+ "flex w-full items-center gap-3 rounded-md px-3 py-2.5 text-left text-sm transition-colors",
732
+ "disabled:cursor-not-allowed disabled:opacity-50",
733
+ active ? "bg-primary-50 text-primary" : "text-foreground hover:bg-primary-50 hover:text-primary"
734
+ ),
745
735
  children: [
746
- /* @__PURE__ */ jsxs("div", { className: "relative w-full sm:w-[180px] sm:min-w-[180px]", ref: dropdownRef, children: [
747
- /* @__PURE__ */ jsxs(
748
- "button",
749
- {
750
- type: "button",
751
- onClick: () => setIsOpen((prev) => !prev),
752
- className: "flex h-10 w-full items-center justify-between rounded-md border border-primary-500 bg-white px-4 text-left text-sm font-semibold text-primary-500 sm:rounded-r-none sm:border-r-0",
753
- "aria-haspopup": "listbox",
754
- "aria-expanded": isOpen,
755
- children: [
756
- /* @__PURE__ */ jsx("span", { className: "text-sm leading-tight", children: selectedLabel }),
757
- /* @__PURE__ */ jsx(
758
- "svg",
759
- {
760
- className: "h-4 w-4 flex-shrink-0 text-primary-500",
761
- viewBox: "0 0 20 20",
762
- fill: "currentColor",
763
- "aria-hidden": "true",
764
- children: /* @__PURE__ */ jsx(
765
- "path",
736
+ multi && /* @__PURE__ */ jsx(
737
+ "input",
738
+ {
739
+ type: "checkbox",
740
+ readOnly: true,
741
+ checked: active,
742
+ tabIndex: -1,
743
+ className: "h-4 w-4 shrink-0 accent-primary"
744
+ }
745
+ ),
746
+ opt.leadingIcon && /* @__PURE__ */ jsx("span", { className: "shrink-0 text-primary [&_svg]:h-[18px] [&_svg]:w-[18px]", children: opt.leadingIcon }),
747
+ /* @__PURE__ */ jsx("span", { className: "flex-1 truncate", children: opt.label })
748
+ ]
749
+ },
750
+ v
751
+ );
752
+ }) });
753
+ var SearchFilterBar = forwardRef(
754
+ function SearchFilterBar2(props, ref) {
755
+ const {
756
+ options,
757
+ searchValue,
758
+ onSearchChange,
759
+ searchPlaceholder = "Busca en la categor\xEDa seleccionada",
760
+ onSearch,
761
+ onClear,
762
+ showClear = true,
763
+ suggestions,
764
+ suggestionsOpen,
765
+ categoryMenuWidth = 280,
766
+ className
767
+ } = props;
768
+ const [catOpen, setCatOpen] = useState(false);
769
+ const [focused, setFocused] = useState(false);
770
+ const inputRef = useRef(null);
771
+ const isMulti = props.categoryMultiSelect === true;
772
+ const categoryLabel = useMemo(() => {
773
+ if (isMulti) {
774
+ const selected = props.selectedOptions;
775
+ if (selected.length === 0) {
776
+ return props.categoryEmptyLabel ?? "Categor\xEDas";
777
+ }
778
+ const labelFn = props.categoryMultiLabel;
779
+ return labelFn?.(selected.length) ?? `${selected.length} elementos...`;
780
+ }
781
+ const v = props.selectedOption;
782
+ return options.find((o) => String(o.value) === v)?.label ?? v;
783
+ }, [isMulti, props, options]);
784
+ const isOptionActive = useCallback(
785
+ (v) => {
786
+ if (isMulti) return props.selectedOptions.includes(v);
787
+ return props.selectedOption === v;
788
+ },
789
+ [isMulti, props]
790
+ );
791
+ const handleSelect = useCallback(
792
+ (v) => {
793
+ if (isMulti) {
794
+ const selected = props.selectedOptions;
795
+ const next = selected.includes(v) ? selected.filter((x) => x !== v) : [...selected, v];
796
+ props.onOptionsChange(next);
797
+ } else {
798
+ props.onOptionChange(v);
799
+ setCatOpen(false);
800
+ }
801
+ },
802
+ [isMulti, props]
803
+ );
804
+ const showSuggestions = suggestionsOpen ?? (focused && searchValue.length > 0 && suggestions !== void 0);
805
+ return /* @__PURE__ */ jsxs("div", { ref, className: cn("relative", className), children: [
806
+ /* @__PURE__ */ jsxs(Popover, { open: catOpen, onOpenChange: setCatOpen, children: [
807
+ /* @__PURE__ */ jsx(PopoverAnchor, { asChild: true, children: /* @__PURE__ */ jsxs(
808
+ "div",
809
+ {
810
+ className: cn(
811
+ "flex h-12 items-center rounded-lg border-[1.5px] bg-background transition-colors",
812
+ catOpen || focused ? "border-primary" : "border-primary-200 hover:border-primary-400"
813
+ ),
814
+ children: [
815
+ /* @__PURE__ */ jsx(PopoverTrigger, { asChild: true, children: /* @__PURE__ */ jsxs(
816
+ "button",
817
+ {
818
+ type: "button",
819
+ className: "flex h-full w-[190px] shrink-0 cursor-pointer items-center gap-3 border-0 bg-transparent px-4 text-left text-sm font-semibold text-primary focus:outline-none",
820
+ "aria-haspopup": "listbox",
821
+ "aria-expanded": catOpen,
822
+ children: [
823
+ /* @__PURE__ */ jsx("span", { className: "flex-1 truncate", children: categoryLabel }),
824
+ /* @__PURE__ */ jsx(
825
+ ChevronDown,
766
826
  {
767
- fillRule: "evenodd",
768
- d: "M5.23 7.21a.75.75 0 0 1 1.06.02L10 11.168l3.71-3.938a.75.75 0 1 1 1.08 1.04l-4.25 4.5a.75.75 0 0 1-1.08 0l-4.25-4.5a.75.75 0 0 1 .02-1.06Z",
769
- clipRule: "evenodd"
827
+ "aria-hidden": "true",
828
+ className: cn(
829
+ "h-3 w-3 shrink-0 transition-transform duration-200",
830
+ catOpen && "rotate-180"
831
+ )
770
832
  }
771
833
  )
772
- }
773
- )
774
- ]
775
- }
776
- ),
777
- isOpen && /* @__PURE__ */ jsx(
778
- "ul",
779
- {
780
- role: "listbox",
781
- className: "absolute z-20 mt-1 max-h-60 w-full overflow-y-auto rounded-md border border-[#d1d5db] bg-white py-1 shadow-lg",
782
- children: options.map((option) => {
783
- const value = String(option.value);
784
- const isSelected = value === selectedOption;
785
- return /* @__PURE__ */ jsx("li", { children: /* @__PURE__ */ jsx(
834
+ ]
835
+ }
836
+ ) }),
837
+ /* @__PURE__ */ jsx("div", { "aria-hidden": "true", className: "h-6 w-px shrink-0 bg-primary-200" }),
838
+ /* @__PURE__ */ jsx(
839
+ "input",
840
+ {
841
+ ref: inputRef,
842
+ type: "text",
843
+ value: searchValue,
844
+ onChange: (e) => onSearchChange(e.target.value),
845
+ onFocus: () => setFocused(true),
846
+ onBlur: () => {
847
+ window.setTimeout(() => setFocused(false), 120);
848
+ },
849
+ onKeyDown: (e) => {
850
+ if (e.key === "Enter") onSearch?.(searchValue);
851
+ },
852
+ placeholder: searchPlaceholder,
853
+ className: "h-full min-w-0 flex-1 border-0 bg-transparent pl-4 pr-3 text-sm text-foreground outline-none placeholder:text-muted-foreground"
854
+ }
855
+ ),
856
+ /* @__PURE__ */ jsxs("div", { className: "flex shrink-0 items-center gap-3 pr-4", children: [
857
+ showClear && searchValue && /* @__PURE__ */ jsx(
786
858
  "button",
787
859
  {
788
860
  type: "button",
861
+ "aria-label": "Limpiar",
789
862
  onClick: () => {
790
- onOptionChange(value);
791
- setIsOpen(false);
863
+ onSearchChange("");
864
+ onClear?.();
865
+ inputRef.current?.focus();
792
866
  },
793
- className: `w-full px-4 py-2 text-left text-sm hover:bg-blue-50 ${isSelected ? "bg-blue-50 font-medium text-primary-500" : "text-[#374151]"}`,
794
- children: option.label
867
+ className: "grid h-6 w-6 cursor-pointer place-items-center border-0 bg-transparent p-0 text-muted-foreground hover:text-foreground",
868
+ children: /* @__PURE__ */ jsx(X, { "aria-hidden": "true", className: "h-5 w-5" })
795
869
  }
796
- ) }, value);
797
- })
798
- }
799
- )
800
- ] }),
801
- /* @__PURE__ */ jsx("div", { className: "w-full sm:max-w-[360px] sm:flex-1", children: /* @__PURE__ */ jsxs("div", { className: "relative flex h-10 w-full items-center rounded-md border border-[#d1d5db] bg-white px-4 sm:rounded-l-none", children: [
802
- /* @__PURE__ */ jsx(
803
- "input",
804
- {
805
- type: "text",
806
- value: searchValue,
807
- onChange: (event) => onSearchChange(event.target.value),
808
- placeholder: searchPlaceholder,
809
- className: "w-full bg-transparent pr-8 text-sm text-gray-500-500 placeholder:text-[#9ca3af] focus:outline-none"
810
- }
811
- ),
812
- /* @__PURE__ */ jsx(
813
- FontAwesomeIcon,
814
- {
815
- icon: faSearch,
816
- className: "pointer-events-none absolute right-3 text-[#c4c8d0]"
817
- }
818
- )
819
- ] }) })
820
- ]
821
- }
822
- );
823
- }
870
+ ),
871
+ /* @__PURE__ */ jsx(
872
+ "button",
873
+ {
874
+ type: "button",
875
+ "aria-label": "Buscar",
876
+ onClick: () => onSearch?.(searchValue),
877
+ className: "grid h-6 w-6 cursor-pointer place-items-center border-0 bg-transparent p-0 text-primary hover:text-primary-600",
878
+ children: /* @__PURE__ */ jsx(Search, { "aria-hidden": "true", className: "h-5 w-5" })
879
+ }
880
+ )
881
+ ] })
882
+ ]
883
+ }
884
+ ) }),
885
+ /* @__PURE__ */ jsx(
886
+ PopoverContent,
887
+ {
888
+ align: "start",
889
+ sideOffset: 6,
890
+ style: { width: categoryMenuWidth },
891
+ className: "p-1.5",
892
+ children: /* @__PURE__ */ jsx(
893
+ SearchCategoryMenu,
894
+ {
895
+ options,
896
+ isActive: isOptionActive,
897
+ onSelect: handleSelect,
898
+ multi: isMulti
899
+ }
900
+ )
901
+ }
902
+ )
903
+ ] }),
904
+ showSuggestions && /* @__PURE__ */ jsx(
905
+ "div",
906
+ {
907
+ className: "absolute inset-x-0 top-full z-20 mt-1.5 overflow-hidden rounded-lg border border-border bg-popover shadow-md",
908
+ onMouseDown: (e) => e.preventDefault(),
909
+ children: suggestions
910
+ }
911
+ )
912
+ ] });
913
+ }
914
+ );
915
+ SearchFilterBar.displayName = "SearchFilterBar";
916
+ var SearchSuggestRow = ({
917
+ children,
918
+ className
919
+ }) => /* @__PURE__ */ jsx("div", { className: cn("border-b border-border px-[18px] py-3 text-sm last:border-0", className), children });
920
+ var SearchSuggestQuery = ({ children }) => /* @__PURE__ */ jsx(SearchSuggestRow, { className: "font-medium text-foreground", children });
921
+ var SearchSuggestHeader = ({
922
+ title,
923
+ action
924
+ }) => /* @__PURE__ */ jsxs(SearchSuggestRow, { className: "flex items-center justify-between font-semibold text-foreground", children: [
925
+ /* @__PURE__ */ jsx("span", { children: title }),
926
+ action && /* @__PURE__ */ jsx("span", { className: "cursor-pointer text-[13.5px] font-medium text-primary underline underline-offset-[3px]", children: action })
927
+ ] });
928
+ var SearchSuggestItem = ({
929
+ active,
930
+ withLinkIcon,
931
+ onClick,
932
+ children,
933
+ className
934
+ }) => /* @__PURE__ */ jsxs(
935
+ "div",
936
+ {
937
+ role: "option",
938
+ "aria-selected": active,
939
+ onClick,
940
+ className: cn(
941
+ "flex cursor-pointer items-center gap-3 border-b border-border px-[18px] py-3 text-sm text-foreground transition-colors last:border-0 hover:bg-primary-50",
942
+ active && "bg-primary-50",
943
+ className
944
+ ),
945
+ children: [
946
+ /* @__PURE__ */ jsx("span", { className: "flex-1", children }),
947
+ withLinkIcon && /* @__PURE__ */ jsx(ArrowUpRight, { "aria-hidden": "true", className: "h-4 w-4 shrink-0 text-foreground" })
948
+ ]
949
+ }
950
+ );
951
+ var SearchSuggestFooter = ({ children }) => /* @__PURE__ */ jsx("div", { className: "border-t border-border px-[18px] py-3 text-xs text-muted-foreground", children });
952
+ var SearchSuggestEmpty = ({
953
+ title,
954
+ description
955
+ }) => /* @__PURE__ */ jsxs("div", { className: "px-[18px] py-7 text-center", children: [
956
+ /* @__PURE__ */ jsx("p", { className: "text-sm font-semibold text-foreground", children: title }),
957
+ description && /* @__PURE__ */ jsx("p", { className: "mx-auto mt-1.5 max-w-[36ch] text-xs text-muted-foreground", children: description })
958
+ ] });
824
959
  var sidebarItemVariants = cva(
825
960
  [
826
961
  "group/sb-item relative flex items-center gap-2.5 text-[13px] cursor-pointer select-none outline-none",
@@ -1151,6 +1286,6 @@ var Tree = forwardRef(function Tree2({ data, defaultExpanded, expanded, onExpand
1151
1286
  });
1152
1287
  Tree.displayName = "Tree";
1153
1288
 
1154
- export { Accordion2 as Accordion, BrandLogo, Content, DEFAULT_FORMAT, DEFAULT_FORMATS, DatePicker, FarmChip, FormCard, Header, Layout, PageHeader, PickerPanel, QueryState, RangePicker, Result, SearchBox, SearchFilterBar, Sidebar, Toaster, Tree, UserAvatar };
1155
- //# sourceMappingURL=chunk-JTFCE6RA.js.map
1156
- //# sourceMappingURL=chunk-JTFCE6RA.js.map
1289
+ export { Accordion2 as Accordion, BrandLogo, Content, DEFAULT_FORMAT, DEFAULT_FORMATS, DatePicker, FarmChip, FormCard, Header, Layout, PageHeader, PickerPanel, QueryState, RangePicker, Result, SearchBox, SearchFilterBar, SearchSuggestEmpty, SearchSuggestFooter, SearchSuggestHeader, SearchSuggestItem, SearchSuggestQuery, SearchSuggestRow, Sidebar, Toaster, Tree, UserAvatar };
1290
+ //# sourceMappingURL=chunk-BZATZ5U5.js.map
1291
+ //# sourceMappingURL=chunk-BZATZ5U5.js.map