@tiny-design/react 1.1.1 → 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.
Files changed (38) hide show
  1. package/es/form/use-form.js +4 -1
  2. package/es/form/use-form.js.map +1 -1
  3. package/es/index.d.ts +2 -1
  4. package/es/index.js +2 -1
  5. package/es/waterfall/hooks/use-breakpoint.js +47 -0
  6. package/es/waterfall/hooks/use-breakpoint.js.map +1 -0
  7. package/es/waterfall/hooks/use-positions.js +28 -0
  8. package/es/waterfall/hooks/use-positions.js.map +1 -0
  9. package/es/waterfall/index.d.ts +2 -0
  10. package/es/waterfall/index.js +9 -0
  11. package/es/waterfall/index.js.map +1 -0
  12. package/es/waterfall/style/_index.scss +22 -0
  13. package/es/waterfall/style/index.css +16 -0
  14. package/es/waterfall/style/index.d.ts +1 -0
  15. package/es/waterfall/style/index.js +1 -0
  16. package/es/waterfall/types.d.ts +35 -0
  17. package/es/waterfall/waterfall.d.ts +8 -0
  18. package/es/waterfall/waterfall.js +128 -0
  19. package/es/waterfall/waterfall.js.map +1 -0
  20. package/lib/form/use-form.js +5 -1
  21. package/lib/form/use-form.js.map +1 -1
  22. package/lib/index.d.ts +2 -1
  23. package/lib/index.js +2 -0
  24. package/lib/waterfall/hooks/use-breakpoint.js +49 -0
  25. package/lib/waterfall/hooks/use-breakpoint.js.map +1 -0
  26. package/lib/waterfall/hooks/use-positions.js +29 -0
  27. package/lib/waterfall/hooks/use-positions.js.map +1 -0
  28. package/lib/waterfall/index.js +8 -0
  29. package/lib/waterfall/index.js.map +1 -0
  30. package/lib/waterfall/style/_index.scss +22 -0
  31. package/lib/waterfall/style/index.css +16 -0
  32. package/lib/waterfall/style/index.d.ts +1 -0
  33. package/lib/waterfall/style/index.js +1 -0
  34. package/lib/waterfall/types.d.ts +35 -0
  35. package/lib/waterfall/waterfall.d.ts +8 -0
  36. package/lib/waterfall/waterfall.js +131 -0
  37. package/lib/waterfall/waterfall.js.map +1 -0
  38. package/package.json +3 -3
@@ -1,7 +1,10 @@
1
1
  import FormInstance from "./form-instance.js";
2
+ import { useRef } from "react";
2
3
  //#region src/form/use-form.ts
3
4
  function useForm(initialValues = {}) {
4
- return [new FormInstance(initialValues)];
5
+ const ref = useRef(null);
6
+ if (!ref.current) ref.current = new FormInstance(initialValues);
7
+ return [ref.current];
5
8
  }
6
9
  //#endregion
7
10
  export { useForm as default };
@@ -1 +1 @@
1
- {"version":3,"file":"use-form.js","names":[],"sources":["../../src/form/use-form.ts"],"sourcesContent":["import FormInstance, { FormValues } from './form-instance';\n\nexport default function useForm(initialValues: FormValues = {}): [FormInstance] {\n return [new FormInstance(initialValues)];\n}\n"],"mappings":";;AAEA,SAAwB,QAAQ,gBAA4B,EAAE,EAAkB;AAC9E,QAAO,CAAC,IAAI,aAAa,cAAc,CAAC"}
1
+ {"version":3,"file":"use-form.js","names":[],"sources":["../../src/form/use-form.ts"],"sourcesContent":["import { useRef } from 'react';\nimport FormInstance, { FormValues } from './form-instance';\n\nexport default function useForm(initialValues: FormValues = {}): [FormInstance] {\n const ref = useRef<FormInstance | null>(null);\n if (!ref.current) {\n ref.current = new FormInstance(initialValues);\n }\n return [ref.current];\n}\n"],"mappings":";;;AAGA,SAAwB,QAAQ,gBAA4B,EAAE,EAAkB;CAC9E,MAAM,MAAM,OAA4B,KAAK;AAC7C,KAAI,CAAC,IAAI,QACP,KAAI,UAAU,IAAI,aAAa,cAAc;AAE/C,QAAO,CAAC,IAAI,QAAQ"}
package/es/index.d.ts CHANGED
@@ -80,10 +80,11 @@ import { Transition } from "./transition/transition.js";
80
80
  import { Tree } from "./tree/tree.js";
81
81
  import { DefaultTypo } from "./typography/index.js";
82
82
  import { Upload } from "./upload/upload.js";
83
+ import { Waterfall } from "./waterfall/waterfall.js";
83
84
  import { withLocale } from "./intl-provider/with-locale.js";
84
85
  import { withSpin } from "./with-spin/with-spin.js";
85
86
  import { en_US } from "./locale/en_US.js";
86
87
  import { zh_CN } from "./locale/zh_CN.js";
87
88
  import { useLocale } from "./_utils/use-locale.js";
88
89
  import { ThemeMode, useTheme } from "./_utils/use-theme.js";
89
- export { Alert, DefaultAnchor as Anchor, AspectRatio, AutoComplete, DefaultAvatar as Avatar, BackTop, Badge, DefaultBreadcrumb as Breadcrumb, DefaultButton as Button, Calendar, DefaultCard as Card, DefaultCarousel as Carousel, Cascader, DefaultCheckbox as Checkbox, Col, DefaultCollapse as Collapse, ColorPicker, ConfigProvider, CopyToClipboard, Countdown, DatePicker, DefaultDesc as Descriptions, Divider, Drawer, Dropdown, Empty, Flex, DefaultFlip as Flip, DefaultForm as Form, Image, DefaultInput as Input, InputNumber, InputOTP, InputPassword, IntlProvider, Keyboard, DefaultLayout as Layout, Link, DefaultList as List, Loader, _default as LoadingBar, type Locale, DefaultMenu as Menu, messageContainer as Message, ModalWithContext as Modal, DefaultSelect as NativeSelect, notificationContainer as Notification, Overlay, Pagination, PopConfirm, Popover, Progress, DefaultRadio as Radio, Rate, Result, Row, ScrollIndicator, Segmented, DefaultSelect$1 as Select, Skeleton, Slider, Space, DefaultSpeedDial as SpeedDial, Split, SplitButton, Statistic, DefaultSteps as Steps, Sticky, StrengthIndicator, Switch, Table, DefaultTabs as Tabs, DefaultTag as Tag, Textarea, type ThemeMode, TimePicker, DefaultTimeline as Timeline, Tooltip, Transfer, Transition, Tree, DefaultTypo as Typography, Upload, en_US, useLocale, useTheme, withLocale, withSpin, zh_CN };
90
+ export { Alert, DefaultAnchor as Anchor, AspectRatio, AutoComplete, DefaultAvatar as Avatar, BackTop, Badge, DefaultBreadcrumb as Breadcrumb, DefaultButton as Button, Calendar, DefaultCard as Card, DefaultCarousel as Carousel, Cascader, DefaultCheckbox as Checkbox, Col, DefaultCollapse as Collapse, ColorPicker, ConfigProvider, CopyToClipboard, Countdown, DatePicker, DefaultDesc as Descriptions, Divider, Drawer, Dropdown, Empty, Flex, DefaultFlip as Flip, DefaultForm as Form, Image, DefaultInput as Input, InputNumber, InputOTP, InputPassword, IntlProvider, Keyboard, DefaultLayout as Layout, Link, DefaultList as List, Loader, _default as LoadingBar, type Locale, DefaultMenu as Menu, messageContainer as Message, ModalWithContext as Modal, DefaultSelect as NativeSelect, notificationContainer as Notification, Overlay, Pagination, PopConfirm, Popover, Progress, DefaultRadio as Radio, Rate, Result, Row, ScrollIndicator, Segmented, DefaultSelect$1 as Select, Skeleton, Slider, Space, DefaultSpeedDial as SpeedDial, Split, SplitButton, Statistic, DefaultSteps as Steps, Sticky, StrengthIndicator, Switch, Table, DefaultTabs as Tabs, DefaultTag as Tag, Textarea, type ThemeMode, TimePicker, DefaultTimeline as Timeline, Tooltip, Transfer, Transition, Tree, DefaultTypo as Typography, Upload, Waterfall, en_US, useLocale, useTheme, withLocale, withSpin, zh_CN };
package/es/index.js CHANGED
@@ -82,8 +82,9 @@ import transfer_default from "./transfer/index.js";
82
82
  import tree_default from "./tree/index.js";
83
83
  import DefaultTypo from "./typography/index.js";
84
84
  import upload_default from "./upload/index.js";
85
+ import waterfall_default from "./waterfall/index.js";
85
86
  import { withLocale } from "./intl-provider/with-locale.js";
86
87
  import { withSpin } from "./with-spin/with-spin.js";
87
88
  import zh_CN from "./locale/zh_CN.js";
88
89
  import { useTheme } from "./_utils/use-theme.js";
89
- export { alert_default as Alert, DefaultAnchor as Anchor, aspect_ratio_default as AspectRatio, auto_complete_default as AutoComplete, DefaultAvatar as Avatar, back_top_default as BackTop, badge_default as Badge, DefaultBreadcrumb as Breadcrumb, DefaultButton as Button, calendar_default as Calendar, DefaultCard as Card, DefaultCarousel as Carousel, cascader_default as Cascader, DefaultCheckbox as Checkbox, col_default as Col, DefaultCollapse as Collapse, color_picker_default as ColorPicker, config_provider_default as ConfigProvider, copy_to_clipboard_default as CopyToClipboard, countdown_default as Countdown, date_picker_default as DatePicker, DefaultDesc as Descriptions, divider_default as Divider, drawer_default as Drawer, dropdown_default as Dropdown, empty_default as Empty, flex_default as Flex, DefaultFlip as Flip, DefaultForm as Form, image_default as Image, DefaultInput as Input, input_number_default as InputNumber, input_otp_default as InputOTP, input_password_default as InputPassword, intl_provider_default as IntlProvider, keyboard_default as Keyboard, DefaultLayout as Layout, link_default as Link, DefaultList as List, loader_default as Loader, loading_bar_default as LoadingBar, DefaultMenu as Menu, message_default as Message, ModalWithContext as Modal, DefaultSelect as NativeSelect, notification_default as Notification, overlay_default as Overlay, pagination_default as Pagination, pop_confirm_default as PopConfirm, popover_default as Popover, Progress, DefaultRadio as Radio, rate_default as Rate, result_default as Result, row_default as Row, scroll_indicator_default as ScrollIndicator, segmented_default as Segmented, DefaultSelect$1 as Select, skeleton_default as Skeleton, slider_default as Slider, space_default as Space, DefaultSpeedDial as SpeedDial, split_default as Split, split_button_default as SplitButton, statistic_default as Statistic, DefaultSteps as Steps, sticky_default as Sticky, strength_indicator_default as StrengthIndicator, switch_default as Switch, table_default as Table, DefaultTabs as Tabs, DefaultTag as Tag, textarea_default as Textarea, time_picker_default as TimePicker, DefaultTimeline as Timeline, tooltip_default as Tooltip, transfer_default as Transfer, transition_default as Transition, tree_default as Tree, DefaultTypo as Typography, upload_default as Upload, en_US, useLocale, useTheme, withLocale, withSpin, zh_CN };
90
+ export { alert_default as Alert, DefaultAnchor as Anchor, aspect_ratio_default as AspectRatio, auto_complete_default as AutoComplete, DefaultAvatar as Avatar, back_top_default as BackTop, badge_default as Badge, DefaultBreadcrumb as Breadcrumb, DefaultButton as Button, calendar_default as Calendar, DefaultCard as Card, DefaultCarousel as Carousel, cascader_default as Cascader, DefaultCheckbox as Checkbox, col_default as Col, DefaultCollapse as Collapse, color_picker_default as ColorPicker, config_provider_default as ConfigProvider, copy_to_clipboard_default as CopyToClipboard, countdown_default as Countdown, date_picker_default as DatePicker, DefaultDesc as Descriptions, divider_default as Divider, drawer_default as Drawer, dropdown_default as Dropdown, empty_default as Empty, flex_default as Flex, DefaultFlip as Flip, DefaultForm as Form, image_default as Image, DefaultInput as Input, input_number_default as InputNumber, input_otp_default as InputOTP, input_password_default as InputPassword, intl_provider_default as IntlProvider, keyboard_default as Keyboard, DefaultLayout as Layout, link_default as Link, DefaultList as List, loader_default as Loader, loading_bar_default as LoadingBar, DefaultMenu as Menu, message_default as Message, ModalWithContext as Modal, DefaultSelect as NativeSelect, notification_default as Notification, overlay_default as Overlay, pagination_default as Pagination, pop_confirm_default as PopConfirm, popover_default as Popover, Progress, DefaultRadio as Radio, rate_default as Rate, result_default as Result, row_default as Row, scroll_indicator_default as ScrollIndicator, segmented_default as Segmented, DefaultSelect$1 as Select, skeleton_default as Skeleton, slider_default as Slider, space_default as Space, DefaultSpeedDial as SpeedDial, split_default as Split, split_button_default as SplitButton, statistic_default as Statistic, DefaultSteps as Steps, sticky_default as Sticky, strength_indicator_default as StrengthIndicator, switch_default as Switch, table_default as Table, DefaultTabs as Tabs, DefaultTag as Tag, textarea_default as Textarea, time_picker_default as TimePicker, DefaultTimeline as Timeline, tooltip_default as Tooltip, transfer_default as Transfer, transition_default as Transition, tree_default as Tree, DefaultTypo as Typography, upload_default as Upload, waterfall_default as Waterfall, en_US, useLocale, useTheme, withLocale, withSpin, zh_CN };
@@ -0,0 +1,47 @@
1
+ import { useEffect, useState } from "react";
2
+ //#region src/waterfall/hooks/use-breakpoint.ts
3
+ const breakpointMap = {
4
+ xxl: "(min-width: 1600px)",
5
+ xl: "(min-width: 1200px)",
6
+ lg: "(min-width: 992px)",
7
+ md: "(min-width: 768px)",
8
+ sm: "(min-width: 576px)",
9
+ xs: "(max-width: 575.98px)"
10
+ };
11
+ const responsiveArray = [
12
+ "xxl",
13
+ "xl",
14
+ "lg",
15
+ "md",
16
+ "sm",
17
+ "xs"
18
+ ];
19
+ function useBreakpoint() {
20
+ const [screens, setScreens] = useState({});
21
+ useEffect(() => {
22
+ if (typeof window === "undefined" || typeof window.matchMedia !== "function") return;
23
+ const queries = /* @__PURE__ */ new Map();
24
+ const update = () => {
25
+ const next = {};
26
+ for (const bp of responsiveArray) {
27
+ const mql = queries.get(bp);
28
+ if (mql) next[bp] = mql.matches;
29
+ }
30
+ setScreens(next);
31
+ };
32
+ for (const bp of responsiveArray) {
33
+ const mql = window.matchMedia(breakpointMap[bp]);
34
+ queries.set(bp, mql);
35
+ mql.addEventListener("change", update);
36
+ }
37
+ update();
38
+ return () => {
39
+ for (const [, mql] of queries) mql.removeEventListener("change", update);
40
+ };
41
+ }, []);
42
+ return screens;
43
+ }
44
+ //#endregion
45
+ export { useBreakpoint as default, responsiveArray };
46
+
47
+ //# sourceMappingURL=use-breakpoint.js.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"use-breakpoint.js","names":[],"sources":["../../../src/waterfall/hooks/use-breakpoint.ts"],"sourcesContent":["import { useEffect, useState } from 'react';\nimport { Breakpoint } from '../types';\n\nconst breakpointMap: Record<Breakpoint, string> = {\n xxl: '(min-width: 1600px)',\n xl: '(min-width: 1200px)',\n lg: '(min-width: 992px)',\n md: '(min-width: 768px)',\n sm: '(min-width: 576px)',\n xs: '(max-width: 575.98px)',\n};\n\nconst responsiveArray: Breakpoint[] = ['xxl', 'xl', 'lg', 'md', 'sm', 'xs'];\n\ntype Screens = Partial<Record<Breakpoint, boolean>>;\n\nexport { responsiveArray };\n\nexport default function useBreakpoint(): Screens {\n const [screens, setScreens] = useState<Screens>({});\n\n useEffect(() => {\n if (typeof window === 'undefined' || typeof window.matchMedia !== 'function') return;\n\n const queries = new Map<Breakpoint, MediaQueryList>();\n\n const update = () => {\n const next: Screens = {};\n for (const bp of responsiveArray) {\n const mql = queries.get(bp);\n if (mql) {\n next[bp] = mql.matches;\n }\n }\n setScreens(next);\n };\n\n for (const bp of responsiveArray) {\n const mql = window.matchMedia(breakpointMap[bp]);\n queries.set(bp, mql);\n mql.addEventListener('change', update);\n }\n\n update();\n\n return () => {\n for (const [, mql] of queries) {\n mql.removeEventListener('change', update);\n }\n };\n }, []);\n\n return screens;\n}\n"],"mappings":";;AAGA,MAAM,gBAA4C;CAChD,KAAK;CACL,IAAI;CACJ,IAAI;CACJ,IAAI;CACJ,IAAI;CACJ,IAAI;CACL;AAED,MAAM,kBAAgC;CAAC;CAAO;CAAM;CAAM;CAAM;CAAM;CAAK;AAM3E,SAAwB,gBAAyB;CAC/C,MAAM,CAAC,SAAS,cAAc,SAAkB,EAAE,CAAC;AAEnD,iBAAgB;AACd,MAAI,OAAO,WAAW,eAAe,OAAO,OAAO,eAAe,WAAY;EAE9E,MAAM,0BAAU,IAAI,KAAiC;EAErD,MAAM,eAAe;GACnB,MAAM,OAAgB,EAAE;AACxB,QAAK,MAAM,MAAM,iBAAiB;IAChC,MAAM,MAAM,QAAQ,IAAI,GAAG;AAC3B,QAAI,IACF,MAAK,MAAM,IAAI;;AAGnB,cAAW,KAAK;;AAGlB,OAAK,MAAM,MAAM,iBAAiB;GAChC,MAAM,MAAM,OAAO,WAAW,cAAc,IAAI;AAChD,WAAQ,IAAI,IAAI,IAAI;AACpB,OAAI,iBAAiB,UAAU,OAAO;;AAGxC,UAAQ;AAER,eAAa;AACX,QAAK,MAAM,GAAG,QAAQ,QACpB,KAAI,oBAAoB,UAAU,OAAO;;IAG5C,EAAE,CAAC;AAEN,QAAO"}
@@ -0,0 +1,28 @@
1
+ import { useMemo } from "react";
2
+ //#region src/waterfall/hooks/use-positions.ts
3
+ function usePositions(itemHeights, columnCount, verticalGutter) {
4
+ return useMemo(() => {
5
+ const columnHeights = new Array(columnCount).fill(0);
6
+ const positions = /* @__PURE__ */ new Map();
7
+ for (let i = 0; i < itemHeights.length; i += 1) {
8
+ const [itemKey, itemHeight, itemColumn] = itemHeights[i];
9
+ let targetColumn = itemColumn ?? columnHeights.indexOf(Math.min(...columnHeights));
10
+ targetColumn = Math.min(targetColumn, columnCount - 1);
11
+ const top = columnHeights[targetColumn];
12
+ positions.set(itemKey, {
13
+ column: targetColumn,
14
+ top
15
+ });
16
+ columnHeights[targetColumn] += itemHeight + verticalGutter;
17
+ }
18
+ return [positions, Math.max(0, Math.max(...columnHeights) - verticalGutter)];
19
+ }, [
20
+ columnCount,
21
+ itemHeights,
22
+ verticalGutter
23
+ ]);
24
+ }
25
+ //#endregion
26
+ export { usePositions as default };
27
+
28
+ //# sourceMappingURL=use-positions.js.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"use-positions.js","names":[],"sources":["../../../src/waterfall/hooks/use-positions.ts"],"sourcesContent":["import { useMemo } from 'react';\n\nexport type ItemHeightData = [key: React.Key, height: number, column?: number];\n\nexport type ItemPositions = Map<\n React.Key,\n {\n column: number;\n top: number;\n }\n>;\n\nexport default function usePositions(\n itemHeights: ItemHeightData[],\n columnCount: number,\n verticalGutter: number,\n): [ItemPositions, number] {\n return useMemo(() => {\n const columnHeights = new Array(columnCount).fill(0) as number[];\n const positions: ItemPositions = new Map();\n\n for (let i = 0; i < itemHeights.length; i += 1) {\n const [itemKey, itemHeight, itemColumn] = itemHeights[i];\n\n let targetColumn = itemColumn ?? columnHeights.indexOf(Math.min(...columnHeights));\n targetColumn = Math.min(targetColumn, columnCount - 1);\n\n const top = columnHeights[targetColumn];\n positions.set(itemKey, { column: targetColumn, top });\n\n columnHeights[targetColumn] += itemHeight + verticalGutter;\n }\n\n const totalHeight = Math.max(0, Math.max(...columnHeights) - verticalGutter);\n return [positions, totalHeight];\n }, [columnCount, itemHeights, verticalGutter]);\n}\n"],"mappings":";;AAYA,SAAwB,aACtB,aACA,aACA,gBACyB;AACzB,QAAO,cAAc;EACnB,MAAM,gBAAgB,IAAI,MAAM,YAAY,CAAC,KAAK,EAAE;EACpD,MAAM,4BAA2B,IAAI,KAAK;AAE1C,OAAK,IAAI,IAAI,GAAG,IAAI,YAAY,QAAQ,KAAK,GAAG;GAC9C,MAAM,CAAC,SAAS,YAAY,cAAc,YAAY;GAEtD,IAAI,eAAe,cAAc,cAAc,QAAQ,KAAK,IAAI,GAAG,cAAc,CAAC;AAClF,kBAAe,KAAK,IAAI,cAAc,cAAc,EAAE;GAEtD,MAAM,MAAM,cAAc;AAC1B,aAAU,IAAI,SAAS;IAAE,QAAQ;IAAc;IAAK,CAAC;AAErD,iBAAc,iBAAiB,aAAa;;AAI9C,SAAO,CAAC,WADY,KAAK,IAAI,GAAG,KAAK,IAAI,GAAG,cAAc,GAAG,eAAe,CAC7C;IAC9B;EAAC;EAAa;EAAa;EAAe,CAAC"}
@@ -0,0 +1,2 @@
1
+ import { Breakpoint, WaterfallItem, WaterfallProps } from "./types.js";
2
+ import { Waterfall } from "./waterfall.js";
@@ -0,0 +1,9 @@
1
+ import '../style/base.css';
2
+ import './style/index.css';
3
+ import Waterfall from "./waterfall.js";
4
+ //#region src/waterfall/index.tsx
5
+ var waterfall_default = Waterfall;
6
+ //#endregion
7
+ export { waterfall_default as default };
8
+
9
+ //# sourceMappingURL=index.js.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"index.js","names":[],"sources":["../../src/waterfall/index.tsx"],"sourcesContent":["import Waterfall from './waterfall';\n\nexport type { WaterfallProps, WaterfallItem, Breakpoint } from './types';\n\nexport default Waterfall;\n"],"mappings":";;AAIA,IAAA,oBAAe"}
@@ -0,0 +1,22 @@
1
+ @use '../../style/variables' as *;
2
+
3
+ .#{$prefix}-waterfall {
4
+ position: relative;
5
+ width: 100%;
6
+ box-sizing: border-box;
7
+
8
+ &__item {
9
+ position: absolute;
10
+ box-sizing: border-box;
11
+ }
12
+
13
+ // Exit animation
14
+ &__item-fade-exit {
15
+ opacity: 1;
16
+ }
17
+
18
+ &__item-fade-exit-active {
19
+ opacity: 0;
20
+ transition: opacity 0.3s ease;
21
+ }
22
+ }
@@ -0,0 +1,16 @@
1
+ .ty-waterfall {
2
+ position: relative;
3
+ width: 100%;
4
+ box-sizing: border-box;
5
+ }
6
+ .ty-waterfall__item {
7
+ position: absolute;
8
+ box-sizing: border-box;
9
+ }
10
+ .ty-waterfall__item-fade-exit {
11
+ opacity: 1;
12
+ }
13
+ .ty-waterfall__item-fade-exit-active {
14
+ opacity: 0;
15
+ transition: opacity 0.3s ease;
16
+ }
@@ -0,0 +1 @@
1
+ export { };
@@ -0,0 +1 @@
1
+ import "./_index.css";
@@ -0,0 +1,35 @@
1
+ import { BaseProps } from "../_utils/props.js";
2
+ import React, { ReactNode } from "react";
3
+
4
+ //#region src/waterfall/types.d.ts
5
+ type Breakpoint = 'xs' | 'sm' | 'md' | 'lg' | 'xl' | 'xxl';
6
+ interface WaterfallItem<T = any> {
7
+ key: React.Key;
8
+ /** Pin this item to a specific column index */
9
+ column?: number;
10
+ /** Direct content — takes priority over itemRender */
11
+ children?: ReactNode;
12
+ /** Custom data passed to itemRender */
13
+ data?: T;
14
+ }
15
+ interface WaterfallProps<T = any> extends BaseProps, Omit<React.PropsWithRef<JSX.IntrinsicElements['div']>, 'children'> {
16
+ /** Number of columns, or responsive breakpoint config. Default: 3 */
17
+ columns?: number | Partial<Record<Breakpoint, number>>;
18
+ /** Spacing between items: number or [horizontal, vertical] */
19
+ gutter?: number | [number, number];
20
+ /** Array of items to render */
21
+ items?: WaterfallItem<T>[];
22
+ /** Custom render function for each item */
23
+ itemRender?: (item: WaterfallItem<T> & {
24
+ index: number;
25
+ column: number;
26
+ }) => ReactNode;
27
+ /** Callback when layout order changes */
28
+ onLayoutChange?: (sortInfo: {
29
+ key: React.Key;
30
+ column: number;
31
+ }[]) => void;
32
+ }
33
+ //#endregion
34
+ export { Breakpoint, WaterfallItem, WaterfallProps };
35
+ //# sourceMappingURL=types.d.ts.map
@@ -0,0 +1,8 @@
1
+ import { WaterfallProps } from "./types.js";
2
+ import React from "react";
3
+
4
+ //#region src/waterfall/waterfall.d.ts
5
+ declare const Waterfall: React.ForwardRefExoticComponent<Omit<WaterfallProps<any>, "ref"> & React.RefAttributes<HTMLDivElement>>;
6
+ //#endregion
7
+ export { Waterfall };
8
+ //# sourceMappingURL=waterfall.d.ts.map
@@ -0,0 +1,128 @@
1
+ import { ConfigContext } from "../config-provider/config-context.js";
2
+ import { getPrefixCls } from "../_utils/general.js";
3
+ import useBreakpoint, { responsiveArray } from "./hooks/use-breakpoint.js";
4
+ import usePositions from "./hooks/use-positions.js";
5
+ import React, { useCallback, useContext, useEffect, useRef, useState } from "react";
6
+ import classNames from "classnames";
7
+ import { jsx } from "react/jsx-runtime";
8
+ import { CSSTransition, TransitionGroup } from "react-transition-group";
9
+ //#region src/waterfall/waterfall.tsx
10
+ const Waterfall = React.forwardRef((props, ref) => {
11
+ const { prefixCls: customisedCls, className, style, columns = 3, gutter = 0, items, itemRender, onLayoutChange, ...otherProps } = props;
12
+ const prefixCls = getPrefixCls("waterfall", useContext(ConfigContext).prefixCls, customisedCls);
13
+ const screens = useBreakpoint();
14
+ const columnCount = React.useMemo(() => {
15
+ if (typeof columns === "number") return columns;
16
+ const matchingBreakpoint = responsiveArray.find((bp) => screens[bp] && columns[bp] !== void 0);
17
+ if (matchingBreakpoint) return columns[matchingBreakpoint];
18
+ return columns.xs ?? 1;
19
+ }, [columns, screens]);
20
+ const [horizontalGutter, verticalGutter] = Array.isArray(gutter) ? gutter : [gutter, gutter];
21
+ const itemRefsMap = useRef(/* @__PURE__ */ new Map());
22
+ const setItemRef = useCallback((key, el) => {
23
+ itemRefsMap.current.set(key, el);
24
+ }, []);
25
+ const [itemHeights, setItemHeights] = useState([]);
26
+ const collectItemSizes = useCallback(() => {
27
+ if (!items || items.length === 0) {
28
+ setItemHeights([]);
29
+ return;
30
+ }
31
+ const nextHeights = items.map((item, index) => {
32
+ const key = item.key ?? index;
33
+ const el = itemRefsMap.current.get(key);
34
+ return [
35
+ key,
36
+ el ? el.getBoundingClientRect().height : 0,
37
+ item.column
38
+ ];
39
+ });
40
+ setItemHeights((prev) => {
41
+ return prev.length === nextHeights.length && prev.every((p, i) => p[0] === nextHeights[i][0] && p[1] === nextHeights[i][1]) ? prev : nextHeights;
42
+ });
43
+ }, [items]);
44
+ const [itemPositions, totalHeight] = usePositions(itemHeights, columnCount, verticalGutter);
45
+ useEffect(() => {
46
+ collectItemSizes();
47
+ }, [
48
+ items,
49
+ columnCount,
50
+ collectItemSizes
51
+ ]);
52
+ useEffect(() => {
53
+ if (typeof ResizeObserver === "undefined") return;
54
+ const observer = new ResizeObserver(() => {
55
+ collectItemSizes();
56
+ });
57
+ for (const [, el] of itemRefsMap.current) if (el) observer.observe(el);
58
+ return () => observer.disconnect();
59
+ }, [items, collectItemSizes]);
60
+ useEffect(() => {
61
+ if (!onLayoutChange || !items || items.length === 0) return;
62
+ if (!items.every((item) => itemPositions.has(item.key))) return;
63
+ onLayoutChange(items.map((item) => ({
64
+ key: item.key,
65
+ column: itemPositions.get(item.key).column
66
+ })));
67
+ }, [
68
+ itemPositions,
69
+ items,
70
+ onLayoutChange
71
+ ]);
72
+ const cls = classNames(prefixCls, className);
73
+ const containerStyle = {
74
+ ...style,
75
+ position: "relative",
76
+ height: totalHeight || void 0
77
+ };
78
+ const mergedItems = items || [];
79
+ return /* @__PURE__ */ jsx("div", {
80
+ ref,
81
+ ...otherProps,
82
+ className: cls,
83
+ style: containerStyle,
84
+ onLoad: collectItemSizes,
85
+ onError: collectItemSizes,
86
+ children: /* @__PURE__ */ jsx(TransitionGroup, {
87
+ component: null,
88
+ children: mergedItems.map((item, index) => {
89
+ const key = item.key ?? index;
90
+ const position = itemPositions.get(key);
91
+ const hasPosition = !!position;
92
+ const columnIndex = position?.column ?? 0;
93
+ const itemStyle = {
94
+ position: "absolute",
95
+ width: `calc((100% - ${horizontalGutter * (columnCount - 1)}px) / ${columnCount})`,
96
+ left: `calc((100% - ${horizontalGutter * (columnCount - 1)}px) / ${columnCount} * ${columnIndex} + ${horizontalGutter * columnIndex}px)`,
97
+ top: position?.top ?? 0,
98
+ transition: hasPosition ? "top 0.3s ease, left 0.3s ease, opacity 0.3s ease" : "none",
99
+ opacity: hasPosition ? 1 : 0
100
+ };
101
+ const content = item.children ?? itemRender?.({
102
+ ...item,
103
+ index,
104
+ column: columnIndex
105
+ });
106
+ return /* @__PURE__ */ jsx(CSSTransition, {
107
+ timeout: 300,
108
+ classNames: `${prefixCls}__item-fade`,
109
+ onExited: () => {
110
+ itemRefsMap.current.delete(key);
111
+ collectItemSizes();
112
+ },
113
+ children: /* @__PURE__ */ jsx("div", {
114
+ ref: (el) => setItemRef(key, el),
115
+ className: `${prefixCls}__item`,
116
+ style: itemStyle,
117
+ children: content
118
+ })
119
+ }, key);
120
+ })
121
+ })
122
+ });
123
+ });
124
+ Waterfall.displayName = "Waterfall";
125
+ //#endregion
126
+ export { Waterfall as default };
127
+
128
+ //# sourceMappingURL=waterfall.js.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"waterfall.js","names":[],"sources":["../../src/waterfall/waterfall.tsx"],"sourcesContent":["import React, { useCallback, useContext, useEffect, useRef, useState } from 'react';\nimport classNames from 'classnames';\nimport { CSSTransition, TransitionGroup } from 'react-transition-group';\nimport { ConfigContext } from '../config-provider/config-context';\nimport { getPrefixCls } from '../_utils/general';\nimport { Breakpoint, WaterfallItem, WaterfallProps } from './types';\nimport useBreakpoint, { responsiveArray } from './hooks/use-breakpoint';\nimport usePositions, { ItemHeightData } from './hooks/use-positions';\n\nconst Waterfall = React.forwardRef<HTMLDivElement, WaterfallProps>((props, ref) => {\n const {\n prefixCls: customisedCls,\n className,\n style,\n columns = 3,\n gutter = 0,\n items,\n itemRender,\n onLayoutChange,\n ...otherProps\n } = props;\n\n const configContext = useContext(ConfigContext);\n const prefixCls = getPrefixCls('waterfall', configContext.prefixCls, customisedCls);\n\n // ===================== Breakpoint =====================\n const screens = useBreakpoint();\n\n const columnCount = React.useMemo<number>(() => {\n if (typeof columns === 'number') {\n return columns;\n }\n\n const matchingBreakpoint = responsiveArray.find(\n (bp: Breakpoint) => screens[bp] && columns[bp] !== undefined,\n );\n\n if (matchingBreakpoint) {\n return columns[matchingBreakpoint] as number;\n }\n\n return columns.xs ?? 1;\n }, [columns, screens]);\n\n // ====================== Gutter ======================\n const [horizontalGutter, verticalGutter] = Array.isArray(gutter)\n ? gutter\n : [gutter, gutter];\n\n // =================== Item Refs ===================\n const itemRefsMap = useRef<Map<React.Key, HTMLDivElement | null>>(new Map());\n\n const setItemRef = useCallback((key: React.Key, el: HTMLDivElement | null) => {\n itemRefsMap.current.set(key, el);\n }, []);\n\n // ================= Item Heights ==================\n const [itemHeights, setItemHeights] = useState<ItemHeightData[]>([]);\n\n const collectItemSizes = useCallback(() => {\n if (!items || items.length === 0) {\n setItemHeights([]);\n return;\n }\n\n const nextHeights = items.map<ItemHeightData>((item, index) => {\n const key = item.key ?? index;\n const el = itemRefsMap.current.get(key);\n const height = el ? el.getBoundingClientRect().height : 0;\n return [key, height, item.column];\n });\n\n setItemHeights((prev) => {\n const isSame =\n prev.length === nextHeights.length &&\n prev.every((p, i) => p[0] === nextHeights[i][0] && p[1] === nextHeights[i][1]);\n return isSame ? prev : nextHeights;\n });\n }, [items]);\n\n // ================= Positions ==================\n const [itemPositions, totalHeight] = usePositions(itemHeights, columnCount, verticalGutter);\n\n // Collect sizes on items/columns change\n useEffect(() => {\n collectItemSizes();\n }, [items, columnCount, collectItemSizes]);\n\n // ResizeObserver for dynamic content\n useEffect(() => {\n if (typeof ResizeObserver === 'undefined') return;\n\n const observer = new ResizeObserver(() => {\n collectItemSizes();\n });\n\n for (const [, el] of itemRefsMap.current) {\n if (el) observer.observe(el);\n }\n\n return () => observer.disconnect();\n }, [items, collectItemSizes]);\n\n // ================ onLayoutChange ================\n useEffect(() => {\n if (!onLayoutChange || !items || items.length === 0) return;\n\n const allPositioned = items.every((item) => itemPositions.has(item.key));\n if (!allPositioned) return;\n\n const sortInfo = items.map((item) => ({\n key: item.key,\n column: itemPositions.get(item.key)!.column,\n }));\n onLayoutChange(sortInfo);\n }, [itemPositions, items, onLayoutChange]);\n\n // ==================== Render ====================\n const cls = classNames(prefixCls, className);\n\n const containerStyle: React.CSSProperties = {\n ...style,\n position: 'relative',\n height: totalHeight || undefined,\n };\n\n const mergedItems = items || [];\n\n return (\n <div\n ref={ref}\n {...otherProps}\n className={cls}\n style={containerStyle}\n onLoad={collectItemSizes}\n onError={collectItemSizes}\n >\n <TransitionGroup component={null}>\n {mergedItems.map((item, index) => {\n const key = item.key ?? index;\n const position = itemPositions.get(key);\n const hasPosition = !!position;\n const columnIndex = position?.column ?? 0;\n\n const itemStyle: React.CSSProperties = {\n position: 'absolute',\n width: `calc((100% - ${horizontalGutter * (columnCount - 1)}px) / ${columnCount})`,\n left: `calc((100% - ${horizontalGutter * (columnCount - 1)}px) / ${columnCount} * ${columnIndex} + ${horizontalGutter * columnIndex}px)`,\n top: position?.top ?? 0,\n // Only transition position changes after initial placement\n transition: hasPosition ? 'top 0.3s ease, left 0.3s ease, opacity 0.3s ease' : 'none',\n // Hide until position is computed so items don't flash at (0,0)\n opacity: hasPosition ? 1 : 0,\n };\n\n const content = item.children ?? itemRender?.({ ...item, index, column: columnIndex });\n\n return (\n <CSSTransition\n key={key}\n timeout={300}\n classNames={`${prefixCls}__item-fade`}\n onExited={() => {\n itemRefsMap.current.delete(key);\n collectItemSizes();\n }}\n >\n <div\n ref={(el) => setItemRef(key, el)}\n className={`${prefixCls}__item`}\n style={itemStyle}\n >\n {content}\n </div>\n </CSSTransition>\n );\n })}\n </TransitionGroup>\n </div>\n );\n});\n\nWaterfall.displayName = 'Waterfall';\n\nexport default Waterfall;\n"],"mappings":"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"}
@@ -1,7 +1,11 @@
1
+ require("../_virtual/_rolldown/runtime.js");
1
2
  const require_form_instance = require("./form-instance.js");
3
+ let react = require("react");
2
4
  //#region src/form/use-form.ts
3
5
  function useForm(initialValues = {}) {
4
- return [new require_form_instance.default(initialValues)];
6
+ const ref = (0, react.useRef)(null);
7
+ if (!ref.current) ref.current = new require_form_instance.default(initialValues);
8
+ return [ref.current];
5
9
  }
6
10
  //#endregion
7
11
  exports.default = useForm;
@@ -1 +1 @@
1
- {"version":3,"file":"use-form.js","names":["FormInstance"],"sources":["../../src/form/use-form.ts"],"sourcesContent":["import FormInstance, { FormValues } from './form-instance';\n\nexport default function useForm(initialValues: FormValues = {}): [FormInstance] {\n return [new FormInstance(initialValues)];\n}\n"],"mappings":";;AAEA,SAAwB,QAAQ,gBAA4B,EAAE,EAAkB;AAC9E,QAAO,CAAC,IAAIA,sBAAAA,QAAa,cAAc,CAAC"}
1
+ {"version":3,"file":"use-form.js","names":["FormInstance"],"sources":["../../src/form/use-form.ts"],"sourcesContent":["import { useRef } from 'react';\nimport FormInstance, { FormValues } from './form-instance';\n\nexport default function useForm(initialValues: FormValues = {}): [FormInstance] {\n const ref = useRef<FormInstance | null>(null);\n if (!ref.current) {\n ref.current = new FormInstance(initialValues);\n }\n return [ref.current];\n}\n"],"mappings":";;;;AAGA,SAAwB,QAAQ,gBAA4B,EAAE,EAAkB;CAC9E,MAAM,OAAA,GAAA,MAAA,QAAkC,KAAK;AAC7C,KAAI,CAAC,IAAI,QACP,KAAI,UAAU,IAAIA,sBAAAA,QAAa,cAAc;AAE/C,QAAO,CAAC,IAAI,QAAQ"}
package/lib/index.d.ts CHANGED
@@ -80,10 +80,11 @@ import { Transition } from "./transition/transition.js";
80
80
  import { Tree } from "./tree/tree.js";
81
81
  import { DefaultTypo } from "./typography/index.js";
82
82
  import { Upload } from "./upload/upload.js";
83
+ import { Waterfall } from "./waterfall/waterfall.js";
83
84
  import { withLocale } from "./intl-provider/with-locale.js";
84
85
  import { withSpin } from "./with-spin/with-spin.js";
85
86
  import { en_US } from "./locale/en_US.js";
86
87
  import { zh_CN } from "./locale/zh_CN.js";
87
88
  import { useLocale } from "./_utils/use-locale.js";
88
89
  import { ThemeMode, useTheme } from "./_utils/use-theme.js";
89
- export { Alert, DefaultAnchor as Anchor, AspectRatio, AutoComplete, DefaultAvatar as Avatar, BackTop, Badge, DefaultBreadcrumb as Breadcrumb, DefaultButton as Button, Calendar, DefaultCard as Card, DefaultCarousel as Carousel, Cascader, DefaultCheckbox as Checkbox, Col, DefaultCollapse as Collapse, ColorPicker, ConfigProvider, CopyToClipboard, Countdown, DatePicker, DefaultDesc as Descriptions, Divider, Drawer, Dropdown, Empty, Flex, DefaultFlip as Flip, DefaultForm as Form, Image, DefaultInput as Input, InputNumber, InputOTP, InputPassword, IntlProvider, Keyboard, DefaultLayout as Layout, Link, DefaultList as List, Loader, _default as LoadingBar, type Locale, DefaultMenu as Menu, messageContainer as Message, ModalWithContext as Modal, DefaultSelect as NativeSelect, notificationContainer as Notification, Overlay, Pagination, PopConfirm, Popover, Progress, DefaultRadio as Radio, Rate, Result, Row, ScrollIndicator, Segmented, DefaultSelect$1 as Select, Skeleton, Slider, Space, DefaultSpeedDial as SpeedDial, Split, SplitButton, Statistic, DefaultSteps as Steps, Sticky, StrengthIndicator, Switch, Table, DefaultTabs as Tabs, DefaultTag as Tag, Textarea, type ThemeMode, TimePicker, DefaultTimeline as Timeline, Tooltip, Transfer, Transition, Tree, DefaultTypo as Typography, Upload, en_US, useLocale, useTheme, withLocale, withSpin, zh_CN };
90
+ export { Alert, DefaultAnchor as Anchor, AspectRatio, AutoComplete, DefaultAvatar as Avatar, BackTop, Badge, DefaultBreadcrumb as Breadcrumb, DefaultButton as Button, Calendar, DefaultCard as Card, DefaultCarousel as Carousel, Cascader, DefaultCheckbox as Checkbox, Col, DefaultCollapse as Collapse, ColorPicker, ConfigProvider, CopyToClipboard, Countdown, DatePicker, DefaultDesc as Descriptions, Divider, Drawer, Dropdown, Empty, Flex, DefaultFlip as Flip, DefaultForm as Form, Image, DefaultInput as Input, InputNumber, InputOTP, InputPassword, IntlProvider, Keyboard, DefaultLayout as Layout, Link, DefaultList as List, Loader, _default as LoadingBar, type Locale, DefaultMenu as Menu, messageContainer as Message, ModalWithContext as Modal, DefaultSelect as NativeSelect, notificationContainer as Notification, Overlay, Pagination, PopConfirm, Popover, Progress, DefaultRadio as Radio, Rate, Result, Row, ScrollIndicator, Segmented, DefaultSelect$1 as Select, Skeleton, Slider, Space, DefaultSpeedDial as SpeedDial, Split, SplitButton, Statistic, DefaultSteps as Steps, Sticky, StrengthIndicator, Switch, Table, DefaultTabs as Tabs, DefaultTag as Tag, Textarea, type ThemeMode, TimePicker, DefaultTimeline as Timeline, Tooltip, Transfer, Transition, Tree, DefaultTypo as Typography, Upload, Waterfall, en_US, useLocale, useTheme, withLocale, withSpin, zh_CN };
package/lib/index.js CHANGED
@@ -83,6 +83,7 @@ const require_index$77 = require("./transfer/index.js");
83
83
  const require_index$78 = require("./tree/index.js");
84
84
  const require_index$79 = require("./typography/index.js");
85
85
  const require_index$80 = require("./upload/index.js");
86
+ const require_index$81 = require("./waterfall/index.js");
86
87
  const require_with_locale = require("./intl-provider/with-locale.js");
87
88
  const require_with_spin = require("./with-spin/with-spin.js");
88
89
  const require_zh_CN = require("./locale/zh_CN.js");
@@ -168,6 +169,7 @@ exports.Transition = require_index;
168
169
  exports.Tree = require_index$78;
169
170
  exports.Typography = require_index$79;
170
171
  exports.Upload = require_index$80;
172
+ exports.Waterfall = require_index$81;
171
173
  exports.en_US = require_en_US;
172
174
  exports.useLocale = require_use_locale.useLocale;
173
175
  exports.useTheme = require_use_theme.useTheme;
@@ -0,0 +1,49 @@
1
+ require("../../_virtual/_rolldown/runtime.js");
2
+ let react = require("react");
3
+ //#region src/waterfall/hooks/use-breakpoint.ts
4
+ const breakpointMap = {
5
+ xxl: "(min-width: 1600px)",
6
+ xl: "(min-width: 1200px)",
7
+ lg: "(min-width: 992px)",
8
+ md: "(min-width: 768px)",
9
+ sm: "(min-width: 576px)",
10
+ xs: "(max-width: 575.98px)"
11
+ };
12
+ const responsiveArray = [
13
+ "xxl",
14
+ "xl",
15
+ "lg",
16
+ "md",
17
+ "sm",
18
+ "xs"
19
+ ];
20
+ function useBreakpoint() {
21
+ const [screens, setScreens] = (0, react.useState)({});
22
+ (0, react.useEffect)(() => {
23
+ if (typeof window === "undefined" || typeof window.matchMedia !== "function") return;
24
+ const queries = /* @__PURE__ */ new Map();
25
+ const update = () => {
26
+ const next = {};
27
+ for (const bp of responsiveArray) {
28
+ const mql = queries.get(bp);
29
+ if (mql) next[bp] = mql.matches;
30
+ }
31
+ setScreens(next);
32
+ };
33
+ for (const bp of responsiveArray) {
34
+ const mql = window.matchMedia(breakpointMap[bp]);
35
+ queries.set(bp, mql);
36
+ mql.addEventListener("change", update);
37
+ }
38
+ update();
39
+ return () => {
40
+ for (const [, mql] of queries) mql.removeEventListener("change", update);
41
+ };
42
+ }, []);
43
+ return screens;
44
+ }
45
+ //#endregion
46
+ exports.default = useBreakpoint;
47
+ exports.responsiveArray = responsiveArray;
48
+
49
+ //# sourceMappingURL=use-breakpoint.js.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"use-breakpoint.js","names":[],"sources":["../../../src/waterfall/hooks/use-breakpoint.ts"],"sourcesContent":["import { useEffect, useState } from 'react';\nimport { Breakpoint } from '../types';\n\nconst breakpointMap: Record<Breakpoint, string> = {\n xxl: '(min-width: 1600px)',\n xl: '(min-width: 1200px)',\n lg: '(min-width: 992px)',\n md: '(min-width: 768px)',\n sm: '(min-width: 576px)',\n xs: '(max-width: 575.98px)',\n};\n\nconst responsiveArray: Breakpoint[] = ['xxl', 'xl', 'lg', 'md', 'sm', 'xs'];\n\ntype Screens = Partial<Record<Breakpoint, boolean>>;\n\nexport { responsiveArray };\n\nexport default function useBreakpoint(): Screens {\n const [screens, setScreens] = useState<Screens>({});\n\n useEffect(() => {\n if (typeof window === 'undefined' || typeof window.matchMedia !== 'function') return;\n\n const queries = new Map<Breakpoint, MediaQueryList>();\n\n const update = () => {\n const next: Screens = {};\n for (const bp of responsiveArray) {\n const mql = queries.get(bp);\n if (mql) {\n next[bp] = mql.matches;\n }\n }\n setScreens(next);\n };\n\n for (const bp of responsiveArray) {\n const mql = window.matchMedia(breakpointMap[bp]);\n queries.set(bp, mql);\n mql.addEventListener('change', update);\n }\n\n update();\n\n return () => {\n for (const [, mql] of queries) {\n mql.removeEventListener('change', update);\n }\n };\n }, []);\n\n return screens;\n}\n"],"mappings":";;;AAGA,MAAM,gBAA4C;CAChD,KAAK;CACL,IAAI;CACJ,IAAI;CACJ,IAAI;CACJ,IAAI;CACJ,IAAI;CACL;AAED,MAAM,kBAAgC;CAAC;CAAO;CAAM;CAAM;CAAM;CAAM;CAAK;AAM3E,SAAwB,gBAAyB;CAC/C,MAAM,CAAC,SAAS,eAAA,GAAA,MAAA,UAAgC,EAAE,CAAC;AAEnD,EAAA,GAAA,MAAA,iBAAgB;AACd,MAAI,OAAO,WAAW,eAAe,OAAO,OAAO,eAAe,WAAY;EAE9E,MAAM,0BAAU,IAAI,KAAiC;EAErD,MAAM,eAAe;GACnB,MAAM,OAAgB,EAAE;AACxB,QAAK,MAAM,MAAM,iBAAiB;IAChC,MAAM,MAAM,QAAQ,IAAI,GAAG;AAC3B,QAAI,IACF,MAAK,MAAM,IAAI;;AAGnB,cAAW,KAAK;;AAGlB,OAAK,MAAM,MAAM,iBAAiB;GAChC,MAAM,MAAM,OAAO,WAAW,cAAc,IAAI;AAChD,WAAQ,IAAI,IAAI,IAAI;AACpB,OAAI,iBAAiB,UAAU,OAAO;;AAGxC,UAAQ;AAER,eAAa;AACX,QAAK,MAAM,GAAG,QAAQ,QACpB,KAAI,oBAAoB,UAAU,OAAO;;IAG5C,EAAE,CAAC;AAEN,QAAO"}
@@ -0,0 +1,29 @@
1
+ require("../../_virtual/_rolldown/runtime.js");
2
+ let react = require("react");
3
+ //#region src/waterfall/hooks/use-positions.ts
4
+ function usePositions(itemHeights, columnCount, verticalGutter) {
5
+ return (0, react.useMemo)(() => {
6
+ const columnHeights = new Array(columnCount).fill(0);
7
+ const positions = /* @__PURE__ */ new Map();
8
+ for (let i = 0; i < itemHeights.length; i += 1) {
9
+ const [itemKey, itemHeight, itemColumn] = itemHeights[i];
10
+ let targetColumn = itemColumn ?? columnHeights.indexOf(Math.min(...columnHeights));
11
+ targetColumn = Math.min(targetColumn, columnCount - 1);
12
+ const top = columnHeights[targetColumn];
13
+ positions.set(itemKey, {
14
+ column: targetColumn,
15
+ top
16
+ });
17
+ columnHeights[targetColumn] += itemHeight + verticalGutter;
18
+ }
19
+ return [positions, Math.max(0, Math.max(...columnHeights) - verticalGutter)];
20
+ }, [
21
+ columnCount,
22
+ itemHeights,
23
+ verticalGutter
24
+ ]);
25
+ }
26
+ //#endregion
27
+ exports.default = usePositions;
28
+
29
+ //# sourceMappingURL=use-positions.js.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"use-positions.js","names":[],"sources":["../../../src/waterfall/hooks/use-positions.ts"],"sourcesContent":["import { useMemo } from 'react';\n\nexport type ItemHeightData = [key: React.Key, height: number, column?: number];\n\nexport type ItemPositions = Map<\n React.Key,\n {\n column: number;\n top: number;\n }\n>;\n\nexport default function usePositions(\n itemHeights: ItemHeightData[],\n columnCount: number,\n verticalGutter: number,\n): [ItemPositions, number] {\n return useMemo(() => {\n const columnHeights = new Array(columnCount).fill(0) as number[];\n const positions: ItemPositions = new Map();\n\n for (let i = 0; i < itemHeights.length; i += 1) {\n const [itemKey, itemHeight, itemColumn] = itemHeights[i];\n\n let targetColumn = itemColumn ?? columnHeights.indexOf(Math.min(...columnHeights));\n targetColumn = Math.min(targetColumn, columnCount - 1);\n\n const top = columnHeights[targetColumn];\n positions.set(itemKey, { column: targetColumn, top });\n\n columnHeights[targetColumn] += itemHeight + verticalGutter;\n }\n\n const totalHeight = Math.max(0, Math.max(...columnHeights) - verticalGutter);\n return [positions, totalHeight];\n }, [columnCount, itemHeights, verticalGutter]);\n}\n"],"mappings":";;;AAYA,SAAwB,aACtB,aACA,aACA,gBACyB;AACzB,SAAA,GAAA,MAAA,eAAqB;EACnB,MAAM,gBAAgB,IAAI,MAAM,YAAY,CAAC,KAAK,EAAE;EACpD,MAAM,4BAA2B,IAAI,KAAK;AAE1C,OAAK,IAAI,IAAI,GAAG,IAAI,YAAY,QAAQ,KAAK,GAAG;GAC9C,MAAM,CAAC,SAAS,YAAY,cAAc,YAAY;GAEtD,IAAI,eAAe,cAAc,cAAc,QAAQ,KAAK,IAAI,GAAG,cAAc,CAAC;AAClF,kBAAe,KAAK,IAAI,cAAc,cAAc,EAAE;GAEtD,MAAM,MAAM,cAAc;AAC1B,aAAU,IAAI,SAAS;IAAE,QAAQ;IAAc;IAAK,CAAC;AAErD,iBAAc,iBAAiB,aAAa;;AAI9C,SAAO,CAAC,WADY,KAAK,IAAI,GAAG,KAAK,IAAI,GAAG,cAAc,GAAG,eAAe,CAC7C;IAC9B;EAAC;EAAa;EAAa;EAAe,CAAC"}
@@ -0,0 +1,8 @@
1
+ require('../style/base.css');
2
+ require('./style/index.css');
3
+ //#region src/waterfall/index.tsx
4
+ var waterfall_default = require("./waterfall.js").default;
5
+ //#endregion
6
+ exports.default = waterfall_default;
7
+
8
+ //# sourceMappingURL=index.js.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"index.js","names":["Waterfall"],"sources":["../../src/waterfall/index.tsx"],"sourcesContent":["import Waterfall from './waterfall';\n\nexport type { WaterfallProps, WaterfallItem, Breakpoint } from './types';\n\nexport default Waterfall;\n"],"mappings":";AAIA,IAAA,8CAAeA"}
@@ -0,0 +1,22 @@
1
+ @use '../../style/variables' as *;
2
+
3
+ .#{$prefix}-waterfall {
4
+ position: relative;
5
+ width: 100%;
6
+ box-sizing: border-box;
7
+
8
+ &__item {
9
+ position: absolute;
10
+ box-sizing: border-box;
11
+ }
12
+
13
+ // Exit animation
14
+ &__item-fade-exit {
15
+ opacity: 1;
16
+ }
17
+
18
+ &__item-fade-exit-active {
19
+ opacity: 0;
20
+ transition: opacity 0.3s ease;
21
+ }
22
+ }
@@ -0,0 +1,16 @@
1
+ .ty-waterfall {
2
+ position: relative;
3
+ width: 100%;
4
+ box-sizing: border-box;
5
+ }
6
+ .ty-waterfall__item {
7
+ position: absolute;
8
+ box-sizing: border-box;
9
+ }
10
+ .ty-waterfall__item-fade-exit {
11
+ opacity: 1;
12
+ }
13
+ .ty-waterfall__item-fade-exit-active {
14
+ opacity: 0;
15
+ transition: opacity 0.3s ease;
16
+ }
@@ -0,0 +1 @@
1
+ export { };
@@ -0,0 +1 @@
1
+ require("./_index.css");
@@ -0,0 +1,35 @@
1
+ import { BaseProps } from "../_utils/props.js";
2
+ import React, { ReactNode } from "react";
3
+
4
+ //#region src/waterfall/types.d.ts
5
+ type Breakpoint = 'xs' | 'sm' | 'md' | 'lg' | 'xl' | 'xxl';
6
+ interface WaterfallItem<T = any> {
7
+ key: React.Key;
8
+ /** Pin this item to a specific column index */
9
+ column?: number;
10
+ /** Direct content — takes priority over itemRender */
11
+ children?: ReactNode;
12
+ /** Custom data passed to itemRender */
13
+ data?: T;
14
+ }
15
+ interface WaterfallProps<T = any> extends BaseProps, Omit<React.PropsWithRef<JSX.IntrinsicElements['div']>, 'children'> {
16
+ /** Number of columns, or responsive breakpoint config. Default: 3 */
17
+ columns?: number | Partial<Record<Breakpoint, number>>;
18
+ /** Spacing between items: number or [horizontal, vertical] */
19
+ gutter?: number | [number, number];
20
+ /** Array of items to render */
21
+ items?: WaterfallItem<T>[];
22
+ /** Custom render function for each item */
23
+ itemRender?: (item: WaterfallItem<T> & {
24
+ index: number;
25
+ column: number;
26
+ }) => ReactNode;
27
+ /** Callback when layout order changes */
28
+ onLayoutChange?: (sortInfo: {
29
+ key: React.Key;
30
+ column: number;
31
+ }[]) => void;
32
+ }
33
+ //#endregion
34
+ export { WaterfallProps };
35
+ //# sourceMappingURL=types.d.ts.map
@@ -0,0 +1,8 @@
1
+ import { WaterfallProps } from "./types.js";
2
+ import React from "react";
3
+
4
+ //#region src/waterfall/waterfall.d.ts
5
+ declare const Waterfall: React.ForwardRefExoticComponent<Omit<WaterfallProps<any>, "ref"> & React.RefAttributes<HTMLDivElement>>;
6
+ //#endregion
7
+ export { Waterfall };
8
+ //# sourceMappingURL=waterfall.d.ts.map
@@ -0,0 +1,131 @@
1
+ const require_runtime = require("../_virtual/_rolldown/runtime.js");
2
+ const require_config_context = require("../config-provider/config-context.js");
3
+ const require_general = require("../_utils/general.js");
4
+ const require_use_breakpoint = require("./hooks/use-breakpoint.js");
5
+ const require_use_positions = require("./hooks/use-positions.js");
6
+ let react = require("react");
7
+ react = require_runtime.__toESM(react);
8
+ let classnames = require("classnames");
9
+ classnames = require_runtime.__toESM(classnames);
10
+ let react_jsx_runtime = require("react/jsx-runtime");
11
+ let react_transition_group = require("react-transition-group");
12
+ //#region src/waterfall/waterfall.tsx
13
+ const Waterfall = react.default.forwardRef((props, ref) => {
14
+ const { prefixCls: customisedCls, className, style, columns = 3, gutter = 0, items, itemRender, onLayoutChange, ...otherProps } = props;
15
+ const prefixCls = require_general.getPrefixCls("waterfall", (0, react.useContext)(require_config_context.ConfigContext).prefixCls, customisedCls);
16
+ const screens = require_use_breakpoint.default();
17
+ const columnCount = react.default.useMemo(() => {
18
+ if (typeof columns === "number") return columns;
19
+ const matchingBreakpoint = require_use_breakpoint.responsiveArray.find((bp) => screens[bp] && columns[bp] !== void 0);
20
+ if (matchingBreakpoint) return columns[matchingBreakpoint];
21
+ return columns.xs ?? 1;
22
+ }, [columns, screens]);
23
+ const [horizontalGutter, verticalGutter] = Array.isArray(gutter) ? gutter : [gutter, gutter];
24
+ const itemRefsMap = (0, react.useRef)(/* @__PURE__ */ new Map());
25
+ const setItemRef = (0, react.useCallback)((key, el) => {
26
+ itemRefsMap.current.set(key, el);
27
+ }, []);
28
+ const [itemHeights, setItemHeights] = (0, react.useState)([]);
29
+ const collectItemSizes = (0, react.useCallback)(() => {
30
+ if (!items || items.length === 0) {
31
+ setItemHeights([]);
32
+ return;
33
+ }
34
+ const nextHeights = items.map((item, index) => {
35
+ const key = item.key ?? index;
36
+ const el = itemRefsMap.current.get(key);
37
+ return [
38
+ key,
39
+ el ? el.getBoundingClientRect().height : 0,
40
+ item.column
41
+ ];
42
+ });
43
+ setItemHeights((prev) => {
44
+ return prev.length === nextHeights.length && prev.every((p, i) => p[0] === nextHeights[i][0] && p[1] === nextHeights[i][1]) ? prev : nextHeights;
45
+ });
46
+ }, [items]);
47
+ const [itemPositions, totalHeight] = require_use_positions.default(itemHeights, columnCount, verticalGutter);
48
+ (0, react.useEffect)(() => {
49
+ collectItemSizes();
50
+ }, [
51
+ items,
52
+ columnCount,
53
+ collectItemSizes
54
+ ]);
55
+ (0, react.useEffect)(() => {
56
+ if (typeof ResizeObserver === "undefined") return;
57
+ const observer = new ResizeObserver(() => {
58
+ collectItemSizes();
59
+ });
60
+ for (const [, el] of itemRefsMap.current) if (el) observer.observe(el);
61
+ return () => observer.disconnect();
62
+ }, [items, collectItemSizes]);
63
+ (0, react.useEffect)(() => {
64
+ if (!onLayoutChange || !items || items.length === 0) return;
65
+ if (!items.every((item) => itemPositions.has(item.key))) return;
66
+ onLayoutChange(items.map((item) => ({
67
+ key: item.key,
68
+ column: itemPositions.get(item.key).column
69
+ })));
70
+ }, [
71
+ itemPositions,
72
+ items,
73
+ onLayoutChange
74
+ ]);
75
+ const cls = (0, classnames.default)(prefixCls, className);
76
+ const containerStyle = {
77
+ ...style,
78
+ position: "relative",
79
+ height: totalHeight || void 0
80
+ };
81
+ const mergedItems = items || [];
82
+ return /* @__PURE__ */ (0, react_jsx_runtime.jsx)("div", {
83
+ ref,
84
+ ...otherProps,
85
+ className: cls,
86
+ style: containerStyle,
87
+ onLoad: collectItemSizes,
88
+ onError: collectItemSizes,
89
+ children: /* @__PURE__ */ (0, react_jsx_runtime.jsx)(react_transition_group.TransitionGroup, {
90
+ component: null,
91
+ children: mergedItems.map((item, index) => {
92
+ const key = item.key ?? index;
93
+ const position = itemPositions.get(key);
94
+ const hasPosition = !!position;
95
+ const columnIndex = position?.column ?? 0;
96
+ const itemStyle = {
97
+ position: "absolute",
98
+ width: `calc((100% - ${horizontalGutter * (columnCount - 1)}px) / ${columnCount})`,
99
+ left: `calc((100% - ${horizontalGutter * (columnCount - 1)}px) / ${columnCount} * ${columnIndex} + ${horizontalGutter * columnIndex}px)`,
100
+ top: position?.top ?? 0,
101
+ transition: hasPosition ? "top 0.3s ease, left 0.3s ease, opacity 0.3s ease" : "none",
102
+ opacity: hasPosition ? 1 : 0
103
+ };
104
+ const content = item.children ?? itemRender?.({
105
+ ...item,
106
+ index,
107
+ column: columnIndex
108
+ });
109
+ return /* @__PURE__ */ (0, react_jsx_runtime.jsx)(react_transition_group.CSSTransition, {
110
+ timeout: 300,
111
+ classNames: `${prefixCls}__item-fade`,
112
+ onExited: () => {
113
+ itemRefsMap.current.delete(key);
114
+ collectItemSizes();
115
+ },
116
+ children: /* @__PURE__ */ (0, react_jsx_runtime.jsx)("div", {
117
+ ref: (el) => setItemRef(key, el),
118
+ className: `${prefixCls}__item`,
119
+ style: itemStyle,
120
+ children: content
121
+ })
122
+ }, key);
123
+ })
124
+ })
125
+ });
126
+ });
127
+ Waterfall.displayName = "Waterfall";
128
+ //#endregion
129
+ exports.default = Waterfall;
130
+
131
+ //# sourceMappingURL=waterfall.js.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"waterfall.js","names":["React","getPrefixCls","ConfigContext","useBreakpoint","responsiveArray","usePositions","TransitionGroup","CSSTransition"],"sources":["../../src/waterfall/waterfall.tsx"],"sourcesContent":["import React, { useCallback, useContext, useEffect, useRef, useState } from 'react';\nimport classNames from 'classnames';\nimport { CSSTransition, TransitionGroup } from 'react-transition-group';\nimport { ConfigContext } from '../config-provider/config-context';\nimport { getPrefixCls } from '../_utils/general';\nimport { Breakpoint, WaterfallItem, WaterfallProps } from './types';\nimport useBreakpoint, { responsiveArray } from './hooks/use-breakpoint';\nimport usePositions, { ItemHeightData } from './hooks/use-positions';\n\nconst Waterfall = React.forwardRef<HTMLDivElement, WaterfallProps>((props, ref) => {\n const {\n prefixCls: customisedCls,\n className,\n style,\n columns = 3,\n gutter = 0,\n items,\n itemRender,\n onLayoutChange,\n ...otherProps\n } = props;\n\n const configContext = useContext(ConfigContext);\n const prefixCls = getPrefixCls('waterfall', configContext.prefixCls, customisedCls);\n\n // ===================== Breakpoint =====================\n const screens = useBreakpoint();\n\n const columnCount = React.useMemo<number>(() => {\n if (typeof columns === 'number') {\n return columns;\n }\n\n const matchingBreakpoint = responsiveArray.find(\n (bp: Breakpoint) => screens[bp] && columns[bp] !== undefined,\n );\n\n if (matchingBreakpoint) {\n return columns[matchingBreakpoint] as number;\n }\n\n return columns.xs ?? 1;\n }, [columns, screens]);\n\n // ====================== Gutter ======================\n const [horizontalGutter, verticalGutter] = Array.isArray(gutter)\n ? gutter\n : [gutter, gutter];\n\n // =================== Item Refs ===================\n const itemRefsMap = useRef<Map<React.Key, HTMLDivElement | null>>(new Map());\n\n const setItemRef = useCallback((key: React.Key, el: HTMLDivElement | null) => {\n itemRefsMap.current.set(key, el);\n }, []);\n\n // ================= Item Heights ==================\n const [itemHeights, setItemHeights] = useState<ItemHeightData[]>([]);\n\n const collectItemSizes = useCallback(() => {\n if (!items || items.length === 0) {\n setItemHeights([]);\n return;\n }\n\n const nextHeights = items.map<ItemHeightData>((item, index) => {\n const key = item.key ?? index;\n const el = itemRefsMap.current.get(key);\n const height = el ? el.getBoundingClientRect().height : 0;\n return [key, height, item.column];\n });\n\n setItemHeights((prev) => {\n const isSame =\n prev.length === nextHeights.length &&\n prev.every((p, i) => p[0] === nextHeights[i][0] && p[1] === nextHeights[i][1]);\n return isSame ? prev : nextHeights;\n });\n }, [items]);\n\n // ================= Positions ==================\n const [itemPositions, totalHeight] = usePositions(itemHeights, columnCount, verticalGutter);\n\n // Collect sizes on items/columns change\n useEffect(() => {\n collectItemSizes();\n }, [items, columnCount, collectItemSizes]);\n\n // ResizeObserver for dynamic content\n useEffect(() => {\n if (typeof ResizeObserver === 'undefined') return;\n\n const observer = new ResizeObserver(() => {\n collectItemSizes();\n });\n\n for (const [, el] of itemRefsMap.current) {\n if (el) observer.observe(el);\n }\n\n return () => observer.disconnect();\n }, [items, collectItemSizes]);\n\n // ================ onLayoutChange ================\n useEffect(() => {\n if (!onLayoutChange || !items || items.length === 0) return;\n\n const allPositioned = items.every((item) => itemPositions.has(item.key));\n if (!allPositioned) return;\n\n const sortInfo = items.map((item) => ({\n key: item.key,\n column: itemPositions.get(item.key)!.column,\n }));\n onLayoutChange(sortInfo);\n }, [itemPositions, items, onLayoutChange]);\n\n // ==================== Render ====================\n const cls = classNames(prefixCls, className);\n\n const containerStyle: React.CSSProperties = {\n ...style,\n position: 'relative',\n height: totalHeight || undefined,\n };\n\n const mergedItems = items || [];\n\n return (\n <div\n ref={ref}\n {...otherProps}\n className={cls}\n style={containerStyle}\n onLoad={collectItemSizes}\n onError={collectItemSizes}\n >\n <TransitionGroup component={null}>\n {mergedItems.map((item, index) => {\n const key = item.key ?? index;\n const position = itemPositions.get(key);\n const hasPosition = !!position;\n const columnIndex = position?.column ?? 0;\n\n const itemStyle: React.CSSProperties = {\n position: 'absolute',\n width: `calc((100% - ${horizontalGutter * (columnCount - 1)}px) / ${columnCount})`,\n left: `calc((100% - ${horizontalGutter * (columnCount - 1)}px) / ${columnCount} * ${columnIndex} + ${horizontalGutter * columnIndex}px)`,\n top: position?.top ?? 0,\n // Only transition position changes after initial placement\n transition: hasPosition ? 'top 0.3s ease, left 0.3s ease, opacity 0.3s ease' : 'none',\n // Hide until position is computed so items don't flash at (0,0)\n opacity: hasPosition ? 1 : 0,\n };\n\n const content = item.children ?? itemRender?.({ ...item, index, column: columnIndex });\n\n return (\n <CSSTransition\n key={key}\n timeout={300}\n classNames={`${prefixCls}__item-fade`}\n onExited={() => {\n itemRefsMap.current.delete(key);\n collectItemSizes();\n }}\n >\n <div\n ref={(el) => setItemRef(key, el)}\n className={`${prefixCls}__item`}\n style={itemStyle}\n >\n {content}\n </div>\n </CSSTransition>\n );\n })}\n </TransitionGroup>\n </div>\n );\n});\n\nWaterfall.displayName = 'Waterfall';\n\nexport default Waterfall;\n"],"mappings":"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"}
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "@tiny-design/react",
3
- "version": "1.1.1",
3
+ "version": "1.2.0",
4
4
  "description": "A friendly UI component set for React",
5
5
  "license": "MIT",
6
6
  "keywords": [
@@ -55,8 +55,8 @@
55
55
  "classnames": "^2.3.1",
56
56
  "react-transition-group": "^4.4.2",
57
57
  "tslib": "^2.3.1",
58
- "@tiny-design/tokens": "1.1.1",
59
- "@tiny-design/icons": "1.1.1"
58
+ "@tiny-design/icons": "1.2.0",
59
+ "@tiny-design/tokens": "1.2.0"
60
60
  },
61
61
  "devDependencies": {
62
62
  "@testing-library/jest-dom": "^6.0.0",