alouette 19.2.0 → 20.0.0

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
Files changed (54) hide show
  1. package/README.md +3 -1
  2. package/dist/definitions/animations/useTransition.d.ts +2 -2
  3. package/dist/definitions/animations/useTransition.d.ts.map +1 -1
  4. package/dist/definitions/expo/ExternalLink.web.d.ts +1 -1
  5. package/dist/definitions/expo/ExternalLink.web.d.ts.map +1 -1
  6. package/dist/definitions/index.d.ts +2 -0
  7. package/dist/definitions/index.d.ts.map +1 -1
  8. package/dist/definitions/ui/inputs/Select.d.ts +4 -0
  9. package/dist/definitions/ui/inputs/Select.d.ts.map +1 -0
  10. package/dist/definitions/ui/inputs/Select.shared.d.ts +30 -0
  11. package/dist/definitions/ui/inputs/Select.shared.d.ts.map +1 -0
  12. package/dist/definitions/ui/inputs/Select.stories.d.ts +23 -0
  13. package/dist/definitions/ui/inputs/Select.stories.d.ts.map +1 -0
  14. package/dist/definitions/ui/inputs/Select.web.d.ts +4 -0
  15. package/dist/definitions/ui/inputs/Select.web.d.ts.map +1 -0
  16. package/dist/definitions/ui/primitives/FlatList.d.ts.map +1 -1
  17. package/dist/definitions/ui/primitives/ScrollView.d.ts.map +1 -1
  18. package/dist/definitions/ui/primitives/ScrollView.stories.d.ts +17 -0
  19. package/dist/definitions/ui/primitives/ScrollView.stories.d.ts.map +1 -0
  20. package/dist/definitions/ui/primitives/SectionList.d.ts.map +1 -1
  21. package/dist/index-browser.es.js +208 -14
  22. package/dist/index-browser.es.js.map +1 -1
  23. package/dist/index-node22.cjs +242 -13
  24. package/dist/index-node22.cjs.map +1 -1
  25. package/dist/index-node22.mjs +243 -15
  26. package/dist/index-node22.mjs.map +1 -1
  27. package/dist/index-react-native.cjs.js +242 -13
  28. package/dist/index-react-native.cjs.js.map +1 -1
  29. package/dist/index-react-native.es.js +243 -15
  30. package/dist/index-react-native.es.js.map +1 -1
  31. package/package.json +77 -76
  32. package/src/index.ts +2 -0
  33. package/src/ui/inputs/Select.shared.tsx +104 -0
  34. package/src/ui/inputs/Select.stories.tsx +135 -0
  35. package/src/ui/inputs/Select.tsx +191 -0
  36. package/src/ui/inputs/Select.web.tsx +159 -0
  37. package/src/ui/primitives/FlatList.tsx +17 -6
  38. package/src/ui/primitives/ScrollView.stories.tsx +92 -0
  39. package/src/ui/primitives/ScrollView.tsx +14 -4
  40. package/src/ui/primitives/SectionList.tsx +15 -5
  41. package/CHANGELOG.md +0 -711
  42. package/skills/alouette-actions/SKILL.md +0 -151
  43. package/skills/alouette-animation/SKILL.md +0 -214
  44. package/skills/alouette-external-links/SKILL.md +0 -108
  45. package/skills/alouette-feedback/SKILL.md +0 -133
  46. package/skills/alouette-forms/SKILL.md +0 -140
  47. package/skills/alouette-icons/SKILL.md +0 -122
  48. package/skills/alouette-layout/SKILL.md +0 -189
  49. package/skills/alouette-layout/references/spacing-radius-shadow.md +0 -53
  50. package/skills/alouette-responsive/SKILL.md +0 -155
  51. package/skills/alouette-setup/SKILL.md +0 -299
  52. package/skills/alouette-theming/SKILL.md +0 -208
  53. package/skills/alouette-theming/references/tokens.md +0 -74
  54. package/skills/alouette-typography/SKILL.md +0 -151
@@ -10,6 +10,7 @@ const reactNativeSafeAreaContext = require('react-native-safe-area-context');
10
10
  const tailwindMerge = require('tailwind-merge');
11
11
  const tailwindVariants = require('tailwind-variants');
12
12
  const CheckRegularIcon = require('alouette-icons/phosphor-icons/CheckRegularIcon');
13
+ const CaretDownRegularIcon = require('alouette-icons/phosphor-icons/CaretDownRegularIcon');
13
14
  const InfoRegularIcon = require('alouette-icons/phosphor-icons/InfoRegularIcon');
14
15
  const WarningRegularIcon = require('alouette-icons/phosphor-icons/WarningRegularIcon');
15
16
  const XRegularIcon = require('alouette-icons/phosphor-icons/XRegularIcon');
@@ -701,21 +702,30 @@ const Paragraph = react.forwardRef(
701
702
  }
702
703
  );
703
704
 
704
- const ScrollView = nativewind.styled(reactNative.ScrollView, {
705
- className: "style",
706
- contentContainerClassName: "contentContainerStyle"
707
- });
705
+ const ScrollView = nativewind.styled(
706
+ reactNative.ScrollView,
707
+ {
708
+ className: "style",
709
+ contentContainerClassName: "contentContainerStyle"
710
+ }
711
+ );
708
712
 
709
- const FlatList = nativewind.styled(reactNative.FlatList, {
710
- className: "style",
711
- contentContainerClassName: "contentContainerStyle",
712
- columnWrapperClassName: "columnWrapperStyle"
713
- });
713
+ const FlatList = nativewind.styled(
714
+ reactNative.FlatList,
715
+ {
716
+ className: "style",
717
+ contentContainerClassName: "contentContainerStyle",
718
+ columnWrapperClassName: "columnWrapperStyle"
719
+ }
720
+ );
714
721
 
715
- const SectionList = nativewind.styled(reactNative.SectionList, {
716
- className: "style",
717
- contentContainerClassName: "contentContainerStyle"
718
- });
722
+ const SectionList = nativewind.styled(
723
+ reactNative.SectionList,
724
+ {
725
+ className: "style",
726
+ contentContainerClassName: "contentContainerStyle"
727
+ }
728
+ );
719
729
 
720
730
  const Stack = react.forwardRef(
721
731
  ({ className, ...props }, ref) => {
@@ -1743,6 +1753,224 @@ function Switch({ accent, ...rest }) {
1743
1753
  return /* @__PURE__ */ jsxRuntime.jsx(AccentScope, { accent, children: /* @__PURE__ */ jsxRuntime.jsx(SwitchInner, { ...rest }) });
1744
1754
  }
1745
1755
 
1756
+ function useControllableValue(controlled, defaultValue, onValueChange) {
1757
+ const [internal, setInternal] = react.useState(defaultValue);
1758
+ const value = controlled ?? internal;
1759
+ const setValue = react.useCallback(
1760
+ (next) => {
1761
+ if (controlled === void 0) {
1762
+ setInternal(next);
1763
+ }
1764
+ if (next !== value) {
1765
+ onValueChange?.(next);
1766
+ }
1767
+ },
1768
+ [controlled, onValueChange, value]
1769
+ );
1770
+ return [value, setValue];
1771
+ }
1772
+ const selectTriggerBaseClassName = [
1773
+ "flex-row items-center justify-between gap-xs",
1774
+ "rounded-md border px-m py-xs min-h-[44px]",
1775
+ "transition-[border-color,outline-color,background-color] duration-200 ease-in"
1776
+ ].join(" ");
1777
+ const triggerLabelVariants = tailwindVariants.tv({
1778
+ base: "flex-1 text-base",
1779
+ variants: {
1780
+ // Mirrors InputText: sharp value, form-placeholder, form-disabled-text.
1781
+ state: {
1782
+ value: "text-sharp",
1783
+ placeholder: "text-form-placeholder",
1784
+ disabled: "text-form-disabled-text"
1785
+ }
1786
+ },
1787
+ defaultVariants: { state: "value" }
1788
+ });
1789
+ function SelectTriggerContent({
1790
+ label,
1791
+ placeholder,
1792
+ disabled
1793
+ }) {
1794
+ const state = (() => {
1795
+ if (label === void 0) return "placeholder";
1796
+ if (disabled) return "disabled";
1797
+ return "value";
1798
+ })();
1799
+ return /* @__PURE__ */ jsxRuntime.jsxs(jsxRuntime.Fragment, { children: [
1800
+ /* @__PURE__ */ jsxRuntime.jsx(Text, { numberOfLines: 1, className: triggerLabelVariants({ state }), children: label ?? placeholder ?? "" }),
1801
+ /* @__PURE__ */ jsxRuntime.jsx(
1802
+ Icon,
1803
+ {
1804
+ icon: /* @__PURE__ */ jsxRuntime.jsx(CaretDownRegularIcon.CaretDownRegularIcon, {}),
1805
+ size: 18,
1806
+ className: disabled ? "text-form-disabled-text" : "text-muted"
1807
+ }
1808
+ )
1809
+ ] });
1810
+ }
1811
+
1812
+ const triggerVariants = tailwindVariants.tv(
1813
+ {
1814
+ base: selectTriggerBaseClassName,
1815
+ variants: {
1816
+ // bg lives in each branch (not the shared base) so the disabled bg never
1817
+ // competes with bg-highlight at equal specificity.
1818
+ disabled: {
1819
+ true: "bg-disabled-interactive-muted border-interactive-outlined-disabled",
1820
+ false: [
1821
+ "bg-highlight",
1822
+ "border-interactive-outlined-pressable",
1823
+ "hover:border-interactive-outlined-hover",
1824
+ "focus:border-interactive-outlined-focus",
1825
+ "active:border-interactive-outlined-active"
1826
+ ].join(" ")
1827
+ }
1828
+ },
1829
+ defaultVariants: { disabled: false }
1830
+ },
1831
+ { twMerge: false }
1832
+ );
1833
+ const optionVariants = tailwindVariants.tv(
1834
+ {
1835
+ base: [
1836
+ "flex-row items-center justify-between gap-xxs rounded-xs px-m py-m my-xxs",
1837
+ "hover:bg-interactive-contained-hover focus:bg-interactive-contained-focus active:bg-interactive-contained-active"
1838
+ ].join(" "),
1839
+ variants: {
1840
+ selected: {
1841
+ true: "bg-interactive-contained-active",
1842
+ false: "bg-interactive-contained-pressable"
1843
+ },
1844
+ disabled: {
1845
+ true: "opacity-50",
1846
+ false: ""
1847
+ }
1848
+ },
1849
+ defaultVariants: { selected: false, disabled: false }
1850
+ },
1851
+ { twMerge: false }
1852
+ );
1853
+ function SelectOptionRow({
1854
+ option,
1855
+ selected,
1856
+ onSelect
1857
+ }) {
1858
+ return /* @__PURE__ */ jsxRuntime.jsxs(
1859
+ reactNative.Pressable,
1860
+ {
1861
+ role: "option",
1862
+ "aria-selected": selected,
1863
+ "aria-disabled": option.disabled === true,
1864
+ disabled: option.disabled,
1865
+ className: optionVariants({ selected, disabled: option.disabled }),
1866
+ onPress: () => {
1867
+ onSelect(option.value);
1868
+ },
1869
+ children: [
1870
+ /* @__PURE__ */ jsxRuntime.jsx(Text, { numberOfLines: 1, className: "flex-1 text-base text-on-accent", children: option.label }),
1871
+ selected ? /* @__PURE__ */ jsxRuntime.jsx(
1872
+ Icon,
1873
+ {
1874
+ icon: /* @__PURE__ */ jsxRuntime.jsx(CheckRegularIcon.CheckRegularIcon, {}),
1875
+ size: 18,
1876
+ className: "text-on-accent"
1877
+ }
1878
+ ) : null
1879
+ ]
1880
+ }
1881
+ );
1882
+ }
1883
+ function SelectInner({
1884
+ options,
1885
+ value,
1886
+ defaultValue,
1887
+ onValueChange,
1888
+ placeholder,
1889
+ disabled,
1890
+ testID,
1891
+ "aria-label": ariaLabel,
1892
+ "aria-labelledby": ariaLabelledby
1893
+ }) {
1894
+ const [current, setValue] = useControllableValue(
1895
+ value,
1896
+ defaultValue,
1897
+ onValueChange
1898
+ );
1899
+ const [open, setOpen] = react.useState(false);
1900
+ const { height: windowHeight } = reactNative.useWindowDimensions();
1901
+ const selected = options.find((option) => option.value === current);
1902
+ const onSelect = (next) => {
1903
+ setValue(next);
1904
+ setOpen(false);
1905
+ };
1906
+ return /* @__PURE__ */ jsxRuntime.jsxs(jsxRuntime.Fragment, { children: [
1907
+ /* @__PURE__ */ jsxRuntime.jsx(
1908
+ InteractiveBox,
1909
+ {
1910
+ withFocusVisibleOutline: true,
1911
+ role: "combobox",
1912
+ "aria-expanded": open,
1913
+ "aria-disabled": disabled === true,
1914
+ disabled,
1915
+ testID,
1916
+ "aria-label": ariaLabel,
1917
+ "aria-labelledby": ariaLabelledby,
1918
+ className: triggerVariants({ disabled }),
1919
+ onPress: () => {
1920
+ setOpen(true);
1921
+ },
1922
+ children: /* @__PURE__ */ jsxRuntime.jsx(
1923
+ SelectTriggerContent,
1924
+ {
1925
+ label: selected?.label,
1926
+ placeholder,
1927
+ disabled
1928
+ }
1929
+ )
1930
+ }
1931
+ ),
1932
+ /* @__PURE__ */ jsxRuntime.jsx(
1933
+ reactNative.Modal,
1934
+ {
1935
+ transparent: true,
1936
+ visible: open,
1937
+ animationType: "fade",
1938
+ onRequestClose: () => {
1939
+ setOpen(false);
1940
+ },
1941
+ children: /* @__PURE__ */ jsxRuntime.jsx(
1942
+ reactNative.Pressable,
1943
+ {
1944
+ className: "flex-1 justify-center bg-translucent px-xl",
1945
+ onPress: () => {
1946
+ setOpen(false);
1947
+ },
1948
+ children: /* @__PURE__ */ jsxRuntime.jsx(reactNative.Pressable, { className: "w-full", "aria-label": ariaLabel, children: /* @__PURE__ */ jsxRuntime.jsx(Surface, { variant: "highlight", shadow: "l", size: "sm", className: "py-xs", children: /* @__PURE__ */ jsxRuntime.jsx(
1949
+ ScrollView,
1950
+ {
1951
+ style: { maxHeight: windowHeight * 0.7 },
1952
+ showsVerticalScrollIndicator: false,
1953
+ children: options.map((option) => /* @__PURE__ */ jsxRuntime.jsx(
1954
+ SelectOptionRow,
1955
+ {
1956
+ option,
1957
+ selected: option.value === current,
1958
+ onSelect
1959
+ },
1960
+ option.value
1961
+ ))
1962
+ }
1963
+ ) }) })
1964
+ }
1965
+ )
1966
+ }
1967
+ )
1968
+ ] });
1969
+ }
1970
+ function Select({ accent, ...rest }) {
1971
+ return /* @__PURE__ */ jsxRuntime.jsx(AccentScope, { accent, children: /* @__PURE__ */ jsxRuntime.jsx(SelectInner, { ...rest }) });
1972
+ }
1973
+
1746
1974
  const badgeVariants = tailwindVariants.tv(
1747
1975
  {
1748
1976
  slots: {
@@ -2103,6 +2331,7 @@ exports.SafeAreaBox = SafeAreaBox;
2103
2331
  exports.ScopedTheme = ScopedTheme;
2104
2332
  exports.ScrollView = ScrollView;
2105
2333
  exports.SectionList = SectionList;
2334
+ exports.Select = Select;
2106
2335
  exports.Separator = Separator;
2107
2336
  exports.Stack = Stack;
2108
2337
  exports.Story = Story;