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
@@ -1,12 +1,13 @@
1
1
  import { jsx, jsxs, Fragment as Fragment$1 } from 'react/jsx-runtime';
2
2
  import { VariableContextProvider, styled as styled$1 } from 'nativewind';
3
3
  import { createContext, useContext, forwardRef, Children, cloneElement, Fragment, useRef, useState, useEffect, isValidElement, useCallback } from 'react';
4
- import { useColorScheme, View as View$1, Text as Text$1, ScrollView as ScrollView$1, FlatList as FlatList$1, SectionList as SectionList$1, Pressable, Platform, TextInput, Switch as Switch$1, useWindowDimensions, Linking } from 'react-native';
4
+ import { useColorScheme, View as View$1, Text as Text$1, ScrollView as ScrollView$1, FlatList as FlatList$1, SectionList as SectionList$1, Pressable, Platform, TextInput, Switch as Switch$1, useWindowDimensions, Modal, Linking } from 'react-native';
5
5
  import { SafeAreaProvider, useSafeAreaInsets } from 'react-native-safe-area-context';
6
6
  export { SafeAreaProvider, useSafeAreaInsets } from 'react-native-safe-area-context';
7
7
  import { extendTailwindMerge, twMerge as twMerge$1 } from 'tailwind-merge';
8
8
  import { tv } from 'tailwind-variants';
9
9
  import { CheckRegularIcon } from 'alouette-icons/phosphor-icons/CheckRegularIcon';
10
+ import { CaretDownRegularIcon } from 'alouette-icons/phosphor-icons/CaretDownRegularIcon';
10
11
  import { InfoRegularIcon } from 'alouette-icons/phosphor-icons/InfoRegularIcon';
11
12
  import { WarningRegularIcon } from 'alouette-icons/phosphor-icons/WarningRegularIcon';
12
13
  import { XRegularIcon } from 'alouette-icons/phosphor-icons/XRegularIcon';
@@ -686,21 +687,30 @@ const Paragraph = forwardRef(
686
687
  }
687
688
  );
688
689
 
689
- const ScrollView = styled$1(ScrollView$1, {
690
- className: "style",
691
- contentContainerClassName: "contentContainerStyle"
692
- });
690
+ const ScrollView = styled$1(
691
+ ScrollView$1,
692
+ {
693
+ className: "style",
694
+ contentContainerClassName: "contentContainerStyle"
695
+ }
696
+ );
693
697
 
694
- const FlatList = styled$1(FlatList$1, {
695
- className: "style",
696
- contentContainerClassName: "contentContainerStyle",
697
- columnWrapperClassName: "columnWrapperStyle"
698
- });
698
+ const FlatList = styled$1(
699
+ FlatList$1,
700
+ {
701
+ className: "style",
702
+ contentContainerClassName: "contentContainerStyle",
703
+ columnWrapperClassName: "columnWrapperStyle"
704
+ }
705
+ );
699
706
 
700
- const SectionList = styled$1(SectionList$1, {
701
- className: "style",
702
- contentContainerClassName: "contentContainerStyle"
703
- });
707
+ const SectionList = styled$1(
708
+ SectionList$1,
709
+ {
710
+ className: "style",
711
+ contentContainerClassName: "contentContainerStyle"
712
+ }
713
+ );
704
714
 
705
715
  const Stack = forwardRef(
706
716
  ({ className, ...props }, ref) => {
@@ -1728,6 +1738,224 @@ function Switch({ accent, ...rest }) {
1728
1738
  return /* @__PURE__ */ jsx(AccentScope, { accent, children: /* @__PURE__ */ jsx(SwitchInner, { ...rest }) });
1729
1739
  }
1730
1740
 
1741
+ function useControllableValue(controlled, defaultValue, onValueChange) {
1742
+ const [internal, setInternal] = useState(defaultValue);
1743
+ const value = controlled ?? internal;
1744
+ const setValue = useCallback(
1745
+ (next) => {
1746
+ if (controlled === void 0) {
1747
+ setInternal(next);
1748
+ }
1749
+ if (next !== value) {
1750
+ onValueChange?.(next);
1751
+ }
1752
+ },
1753
+ [controlled, onValueChange, value]
1754
+ );
1755
+ return [value, setValue];
1756
+ }
1757
+ const selectTriggerBaseClassName = [
1758
+ "flex-row items-center justify-between gap-xs",
1759
+ "rounded-md border px-m py-xs min-h-[44px]",
1760
+ "transition-[border-color,outline-color,background-color] duration-200 ease-in"
1761
+ ].join(" ");
1762
+ const triggerLabelVariants = tv({
1763
+ base: "flex-1 text-base",
1764
+ variants: {
1765
+ // Mirrors InputText: sharp value, form-placeholder, form-disabled-text.
1766
+ state: {
1767
+ value: "text-sharp",
1768
+ placeholder: "text-form-placeholder",
1769
+ disabled: "text-form-disabled-text"
1770
+ }
1771
+ },
1772
+ defaultVariants: { state: "value" }
1773
+ });
1774
+ function SelectTriggerContent({
1775
+ label,
1776
+ placeholder,
1777
+ disabled
1778
+ }) {
1779
+ const state = (() => {
1780
+ if (label === void 0) return "placeholder";
1781
+ if (disabled) return "disabled";
1782
+ return "value";
1783
+ })();
1784
+ return /* @__PURE__ */ jsxs(Fragment$1, { children: [
1785
+ /* @__PURE__ */ jsx(Text, { numberOfLines: 1, className: triggerLabelVariants({ state }), children: label ?? placeholder ?? "" }),
1786
+ /* @__PURE__ */ jsx(
1787
+ Icon,
1788
+ {
1789
+ icon: /* @__PURE__ */ jsx(CaretDownRegularIcon, {}),
1790
+ size: 18,
1791
+ className: disabled ? "text-form-disabled-text" : "text-muted"
1792
+ }
1793
+ )
1794
+ ] });
1795
+ }
1796
+
1797
+ const triggerVariants = tv(
1798
+ {
1799
+ base: selectTriggerBaseClassName,
1800
+ variants: {
1801
+ // bg lives in each branch (not the shared base) so the disabled bg never
1802
+ // competes with bg-highlight at equal specificity.
1803
+ disabled: {
1804
+ true: "bg-disabled-interactive-muted border-interactive-outlined-disabled",
1805
+ false: [
1806
+ "bg-highlight",
1807
+ "border-interactive-outlined-pressable",
1808
+ "hover:border-interactive-outlined-hover",
1809
+ "focus:border-interactive-outlined-focus",
1810
+ "active:border-interactive-outlined-active"
1811
+ ].join(" ")
1812
+ }
1813
+ },
1814
+ defaultVariants: { disabled: false }
1815
+ },
1816
+ { twMerge: false }
1817
+ );
1818
+ const optionVariants = tv(
1819
+ {
1820
+ base: [
1821
+ "flex-row items-center justify-between gap-xxs rounded-xs px-m py-m my-xxs",
1822
+ "hover:bg-interactive-contained-hover focus:bg-interactive-contained-focus active:bg-interactive-contained-active"
1823
+ ].join(" "),
1824
+ variants: {
1825
+ selected: {
1826
+ true: "bg-interactive-contained-active",
1827
+ false: "bg-interactive-contained-pressable"
1828
+ },
1829
+ disabled: {
1830
+ true: "opacity-50",
1831
+ false: ""
1832
+ }
1833
+ },
1834
+ defaultVariants: { selected: false, disabled: false }
1835
+ },
1836
+ { twMerge: false }
1837
+ );
1838
+ function SelectOptionRow({
1839
+ option,
1840
+ selected,
1841
+ onSelect
1842
+ }) {
1843
+ return /* @__PURE__ */ jsxs(
1844
+ Pressable,
1845
+ {
1846
+ role: "option",
1847
+ "aria-selected": selected,
1848
+ "aria-disabled": option.disabled === true,
1849
+ disabled: option.disabled,
1850
+ className: optionVariants({ selected, disabled: option.disabled }),
1851
+ onPress: () => {
1852
+ onSelect(option.value);
1853
+ },
1854
+ children: [
1855
+ /* @__PURE__ */ jsx(Text, { numberOfLines: 1, className: "flex-1 text-base text-on-accent", children: option.label }),
1856
+ selected ? /* @__PURE__ */ jsx(
1857
+ Icon,
1858
+ {
1859
+ icon: /* @__PURE__ */ jsx(CheckRegularIcon, {}),
1860
+ size: 18,
1861
+ className: "text-on-accent"
1862
+ }
1863
+ ) : null
1864
+ ]
1865
+ }
1866
+ );
1867
+ }
1868
+ function SelectInner({
1869
+ options,
1870
+ value,
1871
+ defaultValue,
1872
+ onValueChange,
1873
+ placeholder,
1874
+ disabled,
1875
+ testID,
1876
+ "aria-label": ariaLabel,
1877
+ "aria-labelledby": ariaLabelledby
1878
+ }) {
1879
+ const [current, setValue] = useControllableValue(
1880
+ value,
1881
+ defaultValue,
1882
+ onValueChange
1883
+ );
1884
+ const [open, setOpen] = useState(false);
1885
+ const { height: windowHeight } = useWindowDimensions();
1886
+ const selected = options.find((option) => option.value === current);
1887
+ const onSelect = (next) => {
1888
+ setValue(next);
1889
+ setOpen(false);
1890
+ };
1891
+ return /* @__PURE__ */ jsxs(Fragment$1, { children: [
1892
+ /* @__PURE__ */ jsx(
1893
+ InteractiveBox,
1894
+ {
1895
+ withFocusVisibleOutline: true,
1896
+ role: "combobox",
1897
+ "aria-expanded": open,
1898
+ "aria-disabled": disabled === true,
1899
+ disabled,
1900
+ testID,
1901
+ "aria-label": ariaLabel,
1902
+ "aria-labelledby": ariaLabelledby,
1903
+ className: triggerVariants({ disabled }),
1904
+ onPress: () => {
1905
+ setOpen(true);
1906
+ },
1907
+ children: /* @__PURE__ */ jsx(
1908
+ SelectTriggerContent,
1909
+ {
1910
+ label: selected?.label,
1911
+ placeholder,
1912
+ disabled
1913
+ }
1914
+ )
1915
+ }
1916
+ ),
1917
+ /* @__PURE__ */ jsx(
1918
+ Modal,
1919
+ {
1920
+ transparent: true,
1921
+ visible: open,
1922
+ animationType: "fade",
1923
+ onRequestClose: () => {
1924
+ setOpen(false);
1925
+ },
1926
+ children: /* @__PURE__ */ jsx(
1927
+ Pressable,
1928
+ {
1929
+ className: "flex-1 justify-center bg-translucent px-xl",
1930
+ onPress: () => {
1931
+ setOpen(false);
1932
+ },
1933
+ children: /* @__PURE__ */ jsx(Pressable, { className: "w-full", "aria-label": ariaLabel, children: /* @__PURE__ */ jsx(Surface, { variant: "highlight", shadow: "l", size: "sm", className: "py-xs", children: /* @__PURE__ */ jsx(
1934
+ ScrollView,
1935
+ {
1936
+ style: { maxHeight: windowHeight * 0.7 },
1937
+ showsVerticalScrollIndicator: false,
1938
+ children: options.map((option) => /* @__PURE__ */ jsx(
1939
+ SelectOptionRow,
1940
+ {
1941
+ option,
1942
+ selected: option.value === current,
1943
+ onSelect
1944
+ },
1945
+ option.value
1946
+ ))
1947
+ }
1948
+ ) }) })
1949
+ }
1950
+ )
1951
+ }
1952
+ )
1953
+ ] });
1954
+ }
1955
+ function Select({ accent, ...rest }) {
1956
+ return /* @__PURE__ */ jsx(AccentScope, { accent, children: /* @__PURE__ */ jsx(SelectInner, { ...rest }) });
1957
+ }
1958
+
1731
1959
  const badgeVariants = tv(
1732
1960
  {
1733
1961
  slots: {
@@ -2055,5 +2283,5 @@ function ExternalLink({
2055
2283
  return /* @__PURE__ */ jsx(C, { ...props, onPress: handlePress });
2056
2284
  }
2057
2285
 
2058
- export { AccentScope, AlouetteDecorator, AlouetteProvider, Badge, Box, BreakpointNameEnum, Breakpoints, Button, ConfirmationMessage, ExternalLink, ExternalLinkButton, FlatList, GradientBackground, GradientScrollView, HStack, Icon, IconButton, InfoMessage, InputText, InteractiveBox, InternalLinkButton, Message, Paragraph, PresenceList, PresenceOne, PressableBox, PressableListItem, SafeAreaBox, ScopedTheme, ScrollView, SectionList, Separator, Stack, Story, StoryContainer, StoryDecorator, StoryGrid, StoryTitle, Surface, Switch, SwitchBreakpointsUsingDisplayNone, SwitchBreakpointsUsingNull, Text, TextArea, VStack, View, WarningMessage, animationDurationsMs, styled, themeVariables, useCurrentBreakpointName, useCurrentBreakpointNameFiltered, useCurrentMode, useCurrentTheme, useThemeToken };
2286
+ export { AccentScope, AlouetteDecorator, AlouetteProvider, Badge, Box, BreakpointNameEnum, Breakpoints, Button, ConfirmationMessage, ExternalLink, ExternalLinkButton, FlatList, GradientBackground, GradientScrollView, HStack, Icon, IconButton, InfoMessage, InputText, InteractiveBox, InternalLinkButton, Message, Paragraph, PresenceList, PresenceOne, PressableBox, PressableListItem, SafeAreaBox, ScopedTheme, ScrollView, SectionList, Select, Separator, Stack, Story, StoryContainer, StoryDecorator, StoryGrid, StoryTitle, Surface, Switch, SwitchBreakpointsUsingDisplayNone, SwitchBreakpointsUsingNull, Text, TextArea, VStack, View, WarningMessage, animationDurationsMs, styled, themeVariables, useCurrentBreakpointName, useCurrentBreakpointNameFiltered, useCurrentMode, useCurrentTheme, useThemeToken };
2059
2287
  //# sourceMappingURL=index-node22.mjs.map