@windrun-huaiin/third-ui 14.4.3 → 15.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 (43) hide show
  1. package/dist/fuma/mdx/gradient-button.d.ts +5 -1
  2. package/dist/fuma/mdx/gradient-button.js +10 -4
  3. package/dist/fuma/mdx/gradient-button.mjs +14 -8
  4. package/dist/main/index.d.ts +2 -0
  5. package/dist/main/index.js +10 -0
  6. package/dist/main/index.mjs +5 -0
  7. package/dist/main/pill-select/index.d.ts +4 -0
  8. package/dist/main/pill-select/index.js +13 -0
  9. package/dist/main/pill-select/index.mjs +4 -0
  10. package/dist/main/pill-select/x-filter-pills.d.ts +11 -0
  11. package/dist/main/pill-select/x-filter-pills.js +12 -0
  12. package/dist/main/pill-select/x-filter-pills.mjs +10 -0
  13. package/dist/main/pill-select/x-form-pills.d.ts +12 -0
  14. package/dist/main/pill-select/x-form-pills.js +12 -0
  15. package/dist/main/pill-select/x-form-pills.mjs +10 -0
  16. package/dist/main/pill-select/x-pill-select.d.ts +33 -0
  17. package/dist/main/pill-select/x-pill-select.js +142 -0
  18. package/dist/main/pill-select/x-pill-select.mjs +140 -0
  19. package/dist/main/pill-select/x-token-input.d.ts +12 -0
  20. package/dist/main/pill-select/x-token-input.js +71 -0
  21. package/dist/main/pill-select/x-token-input.mjs +69 -0
  22. package/dist/main/rich-text-expert.mjs +2 -2
  23. package/dist/main/x-button.d.ts +3 -0
  24. package/dist/main/x-button.js +29 -8
  25. package/dist/main/x-button.mjs +32 -11
  26. package/dist/main/x-toggle-button.d.ts +32 -0
  27. package/dist/main/x-toggle-button.js +95 -0
  28. package/dist/main/x-toggle-button.mjs +74 -0
  29. package/dist/node_modules/.pnpm/react-medium-image-zoom@5.4.1_react-dom@19.2.4_react@19.2.4__react@19.2.4/node_modules/react-medium-image-zoom/dist/Controlled.mjs +21 -21
  30. package/dist/node_modules/.pnpm/react-medium-image-zoom@5.4.1_react-dom@19.2.4_react@19.2.4__react@19.2.4/node_modules/react-medium-image-zoom/dist/Uncontrolled.mjs +4 -4
  31. package/dist/node_modules/.pnpm/react-medium-image-zoom@5.4.1_react-dom@19.2.4_react@19.2.4__react@19.2.4/node_modules/react-medium-image-zoom/dist/icons.mjs +5 -5
  32. package/dist/node_modules/.pnpm/swiper@12.1.3/node_modules/swiper/swiper-react.mjs +18 -18
  33. package/package.json +8 -8
  34. package/src/fuma/mdx/gradient-button.tsx +40 -4
  35. package/src/main/index.ts +2 -0
  36. package/src/main/pill-select/index.ts +4 -0
  37. package/src/main/pill-select/x-filter-pills.tsx +36 -0
  38. package/src/main/pill-select/x-form-pills.tsx +39 -0
  39. package/src/main/pill-select/x-pill-select.tsx +360 -0
  40. package/src/main/pill-select/x-token-input.tsx +174 -0
  41. package/src/main/x-button.tsx +64 -8
  42. package/src/main/x-toggle-button.tsx +218 -0
  43. package/src/clerk/patch/optional-auth.ts +0 -24
@@ -1,4 +1,4 @@
1
- import React from 'react';
1
+ import React__default from 'react';
2
2
  import ReactDOM from 'react-dom';
3
3
  import { IEnlarge, ICompress } from './icons.mjs';
4
4
  import { getStyleGhost, getImgSrc, testImg, testImgLoaded, testSvg, adjustSvgIDs, testDiv, getImgAlt, getStyleModalImg } from './utils.mjs';
@@ -11,9 +11,9 @@ const defaultBodyAttrs = {
11
11
  width: '',
12
12
  };
13
13
  function Controlled(props) {
14
- return React.createElement(ControlledBase, { ...props });
14
+ return React__default.createElement(ControlledBase, { ...props });
15
15
  }
16
- class ControlledBase extends React.Component {
16
+ class ControlledBase extends React__default.Component {
17
17
  constructor() {
18
18
  super(...arguments);
19
19
  this.state = {
@@ -24,11 +24,11 @@ class ControlledBase extends React.Component {
24
24
  shouldRefresh: false,
25
25
  styleGhost: {},
26
26
  };
27
- this.refContent = React.createRef();
28
- this.refDialog = React.createRef();
29
- this.refModalContent = React.createRef();
30
- this.refModalImg = React.createRef();
31
- this.refWrap = React.createRef();
27
+ this.refContent = React__default.createRef();
28
+ this.refDialog = React__default.createRef();
29
+ this.refModalContent = React__default.createRef();
30
+ this.refModalImg = React__default.createRef();
31
+ this.refWrap = React__default.createRef();
32
32
  this.imgEl = null;
33
33
  this.isScaling = false;
34
34
  this.prevBodyAttrs = defaultBodyAttrs;
@@ -371,24 +371,24 @@ class ControlledBase extends React.Component {
371
371
  : {};
372
372
  let modalContent = null;
373
373
  if (hasImage) {
374
- const modalImg = isImg || isDiv ? (React.createElement("img", { alt: imgAlt, crossOrigin: imgCrossOrigin, sizes: imgSizes, src: imgSrc, srcSet: imgSrcSet, ...(isZoomImgLoaded && modalState === "LOADED"
374
+ const modalImg = isImg || isDiv ? (React__default.createElement("img", { alt: imgAlt, crossOrigin: imgCrossOrigin, sizes: imgSizes, src: imgSrc, srcSet: imgSrcSet, ...(isZoomImgLoaded && modalState === "LOADED"
375
375
  ? zoomImg
376
- : {}), "data-rmiz-modal-img": "", height: this.styleModalImg.height || undefined, id: idModalImg, ref: refModalImg, style: this.styleModalImg, width: this.styleModalImg.width || undefined })) : isSvg ? (React.createElement("div", { "data-rmiz-modal-img": true, ref: refModalImg, style: this.styleModalImg })) : null;
377
- const modalBtnUnzoom = (React.createElement("button", { "aria-label": a11yNameButtonUnzoom, "data-rmiz-btn-unzoom": "", onClick: handleBtnUnzoomClick, type: "button" },
378
- React.createElement(IconUnzoom, null)));
379
- modalContent = ZoomContent ? (React.createElement(ZoomContent, { buttonUnzoom: modalBtnUnzoom, modalState: modalState, img: modalImg, isZoomImgLoaded: isZoomImgLoaded, onUnzoom: handleUnzoom })) : (React.createElement(React.Fragment, null,
376
+ : {}), "data-rmiz-modal-img": "", height: this.styleModalImg.height || undefined, id: idModalImg, ref: refModalImg, style: this.styleModalImg, width: this.styleModalImg.width || undefined })) : isSvg ? (React__default.createElement("div", { "data-rmiz-modal-img": true, ref: refModalImg, style: this.styleModalImg })) : null;
377
+ const modalBtnUnzoom = (React__default.createElement("button", { "aria-label": a11yNameButtonUnzoom, "data-rmiz-btn-unzoom": "", onClick: handleBtnUnzoomClick, type: "button" },
378
+ React__default.createElement(IconUnzoom, null)));
379
+ modalContent = ZoomContent ? (React__default.createElement(ZoomContent, { buttonUnzoom: modalBtnUnzoom, modalState: modalState, img: modalImg, isZoomImgLoaded: isZoomImgLoaded, onUnzoom: handleUnzoom })) : (React__default.createElement(React__default.Fragment, null,
380
380
  modalImg,
381
381
  modalBtnUnzoom));
382
382
  }
383
- return (React.createElement(WrapElement, { "aria-owns": idModal, "data-rmiz": "", ref: refWrap },
384
- React.createElement(WrapElement, { "data-rmiz-content": dataContentState, ref: refContent, style: styleContent }, children),
385
- hasImage && (React.createElement(WrapElement, { "data-rmiz-ghost": "", style: styleGhost },
386
- React.createElement("button", { "aria-label": labelBtnZoom, "data-rmiz-btn-zoom": "", onClick: handleZoom, type: "button" },
387
- React.createElement(IconZoom, null)))),
383
+ return (React__default.createElement(WrapElement, { "aria-owns": idModal, "data-rmiz": "", ref: refWrap },
384
+ React__default.createElement(WrapElement, { "data-rmiz-content": dataContentState, ref: refContent, style: styleContent }, children),
385
+ hasImage && (React__default.createElement(WrapElement, { "data-rmiz-ghost": "", style: styleGhost },
386
+ React__default.createElement("button", { "aria-label": labelBtnZoom, "data-rmiz-btn-zoom": "", onClick: handleZoom, type: "button" },
387
+ React__default.createElement(IconZoom, null)))),
388
388
  hasImage &&
389
- ReactDOM.createPortal(React.createElement("dialog", { "aria-labelledby": idModalImg, "aria-modal": "true", className: classDialog, "data-rmiz-modal": "", id: idModal, onClick: handleDialogClick, onClose: handleDialogClose, onCancel: handleDialogCancel, ref: refDialog, role: "dialog" },
390
- React.createElement("div", { "data-rmiz-modal-overlay": dataOverlayState }),
391
- React.createElement("div", { "data-rmiz-modal-content": "", ref: refModalContent }, modalContent)), this.getDialogContainer())));
389
+ ReactDOM.createPortal(React__default.createElement("dialog", { "aria-labelledby": idModalImg, "aria-modal": "true", className: classDialog, "data-rmiz-modal": "", id: idModal, onClick: handleDialogClick, onClose: handleDialogClose, onCancel: handleDialogCancel, ref: refDialog, role: "dialog" },
390
+ React__default.createElement("div", { "data-rmiz-modal-overlay": dataOverlayState }),
391
+ React__default.createElement("div", { "data-rmiz-modal-content": "", ref: refModalContent }, modalContent)), this.getDialogContainer())));
392
392
  }
393
393
  componentDidMount() {
394
394
  this.setId();
@@ -1,13 +1,13 @@
1
- import React from 'react';
1
+ import React__default from 'react';
2
2
  import { Controlled } from './Controlled.mjs';
3
3
 
4
4
  function Uncontrolled({ onZoomChange, ...props }) {
5
- const [isZoomed, setIsZoomed] = React.useState(false);
6
- const handleZoomChange = React.useCallback((value, { event }) => {
5
+ const [isZoomed, setIsZoomed] = React__default.useState(false);
6
+ const handleZoomChange = React__default.useCallback((value, { event }) => {
7
7
  setIsZoomed(value);
8
8
  onZoomChange?.(value, { event });
9
9
  }, [onZoomChange]);
10
- return (React.createElement(Controlled, { ...props, isZoomed: isZoomed, onZoomChange: handleZoomChange }));
10
+ return (React__default.createElement(Controlled, { ...props, isZoomed: isZoomed, onZoomChange: handleZoomChange }));
11
11
  }
12
12
 
13
13
  export { Uncontrolled };
@@ -1,12 +1,12 @@
1
- import React from 'react';
1
+ import React__default from 'react';
2
2
 
3
3
  function ICompress() {
4
- return (React.createElement("svg", { "aria-hidden": "true", "data-rmiz-btn-unzoom-icon": true, fill: "currentColor", focusable: "false", viewBox: "0 0 16 16", xmlns: "http://www.w3.org/2000/svg" },
5
- React.createElement("path", { d: "M 14.144531 1.148438 L 9 6.292969 L 9 3 L 8 3 L 8 8 L 13 8 L 13 7 L 9.707031 7 L 14.855469 1.851563 Z M 8 8 L 3 8 L 3 9 L 6.292969 9 L 1.148438 14.144531 L 1.851563 14.855469 L 7 9.707031 L 7 13 L 8 13 Z" })));
4
+ return (React__default.createElement("svg", { "aria-hidden": "true", "data-rmiz-btn-unzoom-icon": true, fill: "currentColor", focusable: "false", viewBox: "0 0 16 16", xmlns: "http://www.w3.org/2000/svg" },
5
+ React__default.createElement("path", { d: "M 14.144531 1.148438 L 9 6.292969 L 9 3 L 8 3 L 8 8 L 13 8 L 13 7 L 9.707031 7 L 14.855469 1.851563 Z M 8 8 L 3 8 L 3 9 L 6.292969 9 L 1.148438 14.144531 L 1.851563 14.855469 L 7 9.707031 L 7 13 L 8 13 Z" })));
6
6
  }
7
7
  function IEnlarge() {
8
- return (React.createElement("svg", { "aria-hidden": "true", "data-rmiz-btn-zoom-icon": true, fill: "currentColor", focusable: "false", viewBox: "0 0 16 16", xmlns: "http://www.w3.org/2000/svg" },
9
- React.createElement("path", { d: "M 9 1 L 9 2 L 12.292969 2 L 2 12.292969 L 2 9 L 1 9 L 1 14 L 6 14 L 6 13 L 2.707031 13 L 13 2.707031 L 13 6 L 14 6 L 14 1 Z" })));
8
+ return (React__default.createElement("svg", { "aria-hidden": "true", "data-rmiz-btn-zoom-icon": true, fill: "currentColor", focusable: "false", viewBox: "0 0 16 16", xmlns: "http://www.w3.org/2000/svg" },
9
+ React__default.createElement("path", { d: "M 9 1 L 9 2 L 12.292969 2 L 2 12.292969 L 2 9 L 1 9 L 1 14 L 6 14 L 6 13 L 2.707031 13 L 13 2.707031 L 13 6 L 14 6 L 14 1 Z" })));
10
10
  }
11
11
 
12
12
  export { ICompress, IEnlarge };
@@ -1,4 +1,4 @@
1
- import React, { forwardRef, useState, useRef, useEffect, createContext, useLayoutEffect } from 'react';
1
+ import React__default, { forwardRef, useState, useRef, useEffect, createContext, useLayoutEffect } from 'react';
2
2
  import { S as Swiper$1 } from './shared/swiper-core.mjs';
3
3
  import { g as getParams, m as mountSwiper, a as getChangedParams, u as updateOnVirtualData } from './shared/update-on-virtual-data.mjs';
4
4
  import { d as uniqueClasses, w as wrapperClass, n as needsNavigation, b as needsScrollbar, a as needsPagination, e as extend, u as updateSwiper } from './shared/update-swiper.mjs';
@@ -36,7 +36,7 @@ function isChildSwiperSlide(child) {
36
36
  }
37
37
  function processChildren(c) {
38
38
  const slides = [];
39
- React.Children.toArray(c).forEach(child => {
39
+ React__default.Children.toArray(c).forEach(child => {
40
40
  if (isChildSwiperSlide(child)) {
41
41
  slides.push(child);
42
42
  } else if (child.props && child.props.children) {
@@ -53,7 +53,7 @@ function getChildren(c) {
53
53
  'wrapper-start': [],
54
54
  'wrapper-end': []
55
55
  };
56
- React.Children.toArray(c).forEach(child => {
56
+ React__default.Children.toArray(c).forEach(child => {
57
57
  if (isChildSwiperSlide(child)) {
58
58
  slides.push(child);
59
59
  } else if (child.props && child.props.slot && slots[child.props.slot]) {
@@ -105,7 +105,7 @@ function renderVirtual(swiper, slides, virtualData) {
105
105
  }
106
106
  }
107
107
  return slidesToRender.map((child, index) => {
108
- return /*#__PURE__*/React.cloneElement(child, {
108
+ return /*#__PURE__*/React__default.cloneElement(child, {
109
109
  swiper,
110
110
  style,
111
111
  key: child.props.virtualIndex || child.key || `slide-${index}`
@@ -276,29 +276,29 @@ const Swiper = /*#__PURE__*/forwardRef(({
276
276
  return renderVirtual(swiperRef.current, slides, virtualData);
277
277
  }
278
278
  return slides.map((child, index) => {
279
- return /*#__PURE__*/React.cloneElement(child, {
279
+ return /*#__PURE__*/React__default.cloneElement(child, {
280
280
  swiper: swiperRef.current,
281
281
  swiperSlideIndex: index
282
282
  });
283
283
  });
284
284
  }
285
- return /*#__PURE__*/React.createElement(Tag, _extends({
285
+ return /*#__PURE__*/React__default.createElement(Tag, _extends({
286
286
  ref: swiperElRef,
287
287
  className: uniqueClasses(`${containerClasses}${className ? ` ${className}` : ''}`)
288
- }, restProps), /*#__PURE__*/React.createElement(SwiperContext.Provider, {
288
+ }, restProps), /*#__PURE__*/React__default.createElement(SwiperContext.Provider, {
289
289
  value: swiperRef.current
290
- }, slots['container-start'], /*#__PURE__*/React.createElement(WrapperTag, {
290
+ }, slots['container-start'], /*#__PURE__*/React__default.createElement(WrapperTag, {
291
291
  className: wrapperClass(swiperParams.wrapperClass)
292
- }, slots['wrapper-start'], renderSlides(), slots['wrapper-end']), needsNavigation(swiperParams) && /*#__PURE__*/React.createElement(React.Fragment, null, /*#__PURE__*/React.createElement("div", {
292
+ }, slots['wrapper-start'], renderSlides(), slots['wrapper-end']), needsNavigation(swiperParams) && /*#__PURE__*/React__default.createElement(React__default.Fragment, null, /*#__PURE__*/React__default.createElement("div", {
293
293
  ref: prevElRef,
294
294
  className: "swiper-button-prev"
295
- }), /*#__PURE__*/React.createElement("div", {
295
+ }), /*#__PURE__*/React__default.createElement("div", {
296
296
  ref: nextElRef,
297
297
  className: "swiper-button-next"
298
- })), needsScrollbar(swiperParams) && /*#__PURE__*/React.createElement("div", {
298
+ })), needsScrollbar(swiperParams) && /*#__PURE__*/React__default.createElement("div", {
299
299
  ref: scrollbarElRef,
300
300
  className: "swiper-scrollbar"
301
- }), needsPagination(swiperParams) && /*#__PURE__*/React.createElement("div", {
301
+ }), needsPagination(swiperParams) && /*#__PURE__*/React__default.createElement("div", {
302
302
  ref: paginationElRef,
303
303
  className: "swiper-pagination"
304
304
  }), slots['container-end']));
@@ -364,24 +364,24 @@ const SwiperSlide = /*#__PURE__*/forwardRef(({
364
364
  const onLoad = () => {
365
365
  setLazyLoaded(true);
366
366
  };
367
- return /*#__PURE__*/React.createElement(Tag, _extends({
367
+ return /*#__PURE__*/React__default.createElement(Tag, _extends({
368
368
  ref: slideElRef,
369
369
  className: uniqueClasses(`${slideClasses}${className ? ` ${className}` : ''}`),
370
370
  "data-swiper-slide-index": virtualIndex,
371
371
  onLoad: onLoad
372
- }, rest), zoom && /*#__PURE__*/React.createElement(SwiperSlideContext.Provider, {
372
+ }, rest), zoom && /*#__PURE__*/React__default.createElement(SwiperSlideContext.Provider, {
373
373
  value: slideData
374
- }, /*#__PURE__*/React.createElement("div", {
374
+ }, /*#__PURE__*/React__default.createElement("div", {
375
375
  className: "swiper-zoom-container",
376
376
  "data-swiper-zoom": typeof zoom === 'number' ? zoom : undefined
377
- }, renderChildren(), lazy && !lazyLoaded && /*#__PURE__*/React.createElement("div", {
377
+ }, renderChildren(), lazy && !lazyLoaded && /*#__PURE__*/React__default.createElement("div", {
378
378
  className: "swiper-lazy-preloader",
379
379
  ref: node => {
380
380
  if (node) node.lazyPreloaderManaged = true;
381
381
  }
382
- }))), !zoom && /*#__PURE__*/React.createElement(SwiperSlideContext.Provider, {
382
+ }))), !zoom && /*#__PURE__*/React__default.createElement(SwiperSlideContext.Provider, {
383
383
  value: slideData
384
- }, renderChildren(), lazy && !lazyLoaded && /*#__PURE__*/React.createElement("div", {
384
+ }, renderChildren(), lazy && !lazyLoaded && /*#__PURE__*/React__default.createElement("div", {
385
385
  className: "swiper-lazy-preloader",
386
386
  ref: node => {
387
387
  if (node) node.lazyPreloaderManaged = true;
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "@windrun-huaiin/third-ui",
3
- "version": "14.4.3",
3
+ "version": "15.0.0",
4
4
  "description": "Third-party integrated UI components for windrun-huaiin projects",
5
5
  "main": "./dist/index.js",
6
6
  "module": "./dist/index.mjs",
@@ -16,11 +16,6 @@
16
16
  "import": "./dist/clerk/server.mjs",
17
17
  "require": "./dist/clerk/server.js"
18
18
  },
19
- "./clerk/patch/optional-auth": {
20
- "types": "./dist/clerk/patch/optional-auth.d.ts",
21
- "import": "./dist/clerk/patch/optional-auth.mjs",
22
- "require": "./dist/clerk/patch/optional-auth.js"
23
- },
24
19
  "./fingerprint": {
25
20
  "types": "./dist/clerk/fingerprint/index.d.ts",
26
21
  "import": "./dist/clerk/fingerprint/index.mjs",
@@ -36,6 +31,11 @@
36
31
  "import": "./dist/main/index.mjs",
37
32
  "require": "./dist/main/index.js"
38
33
  },
34
+ "./main/pill-select": {
35
+ "types": "./dist/main/pill-select/index.d.ts",
36
+ "import": "./dist/main/pill-select/index.mjs",
37
+ "require": "./dist/main/pill-select/index.js"
38
+ },
39
39
  "./main/server": {
40
40
  "types": "./dist/main/server.d.ts",
41
41
  "import": "./dist/main/server.mjs",
@@ -87,8 +87,8 @@
87
87
  "react-medium-image-zoom": "^5.4.1",
88
88
  "swiper": "^12.1.2",
89
89
  "zod": "^4.3.6",
90
- "@windrun-huaiin/base-ui": "^14.0.3",
91
- "@windrun-huaiin/lib": "^14.0.1"
90
+ "@windrun-huaiin/lib": "^15.0.0",
91
+ "@windrun-huaiin/base-ui": "^15.0.0"
92
92
  },
93
93
  "peerDependencies": {
94
94
  "clsx": "^2.1.1",
@@ -2,13 +2,23 @@
2
2
 
3
3
  import { cn } from '@windrun-huaiin/lib/utils';
4
4
  import { globalLucideIcons as icons } from "@windrun-huaiin/base-ui/components/server";
5
- import { themeButtonGradientClass, themeButtonGradientHoverClass } from "@windrun-huaiin/base-ui/lib";
5
+ import {
6
+ themeBgColor,
7
+ themeBorderColor,
8
+ themeButtonGradientClass,
9
+ themeButtonGradientHoverClass,
10
+ themeIconColor,
11
+ themeMainBgColor,
12
+ } from "@windrun-huaiin/base-ui/lib";
6
13
  import Link from "next/link";
7
14
  import React, { useState } from 'react';
8
15
 
16
+ type GradientButtonVariant = 'default' | 'soft' | 'subtle';
17
+
9
18
  export interface GradientButtonProps {
10
19
  title: React.ReactNode;
11
20
  icon?: React.ReactNode;
21
+ iconForcePosition?: 'left' | 'right';
12
22
  align?: 'left' | 'center' | 'right';
13
23
  disabled?: boolean;
14
24
  className?: string;
@@ -22,11 +32,13 @@ export interface GradientButtonProps {
22
32
  onClick?: () => void | Promise<void>;
23
33
  loadingText?: React.ReactNode;
24
34
  preventDoubleClick?: boolean;
35
+ variant?: GradientButtonVariant;
25
36
  }
26
37
 
27
38
  export function GradientButton({
28
39
  title,
29
40
  icon,
41
+ iconForcePosition,
30
42
  align = 'left',
31
43
  disabled = false,
32
44
  className = "",
@@ -37,12 +49,16 @@ export function GradientButton({
37
49
  loadingText,
38
50
  preventDoubleClick = true,
39
51
  iconClassName,
52
+ variant = 'default',
40
53
  }: GradientButtonProps) {
41
54
  const [isLoading, setIsLoading] = useState(false);
42
55
  const actualLoadingText = loadingText || title?.toString().trim() || 'Loading...'
43
56
 
44
57
  const defaultIconClass = "h-4 w-4";
45
- const finalIconClass = cn("text-white", iconClassName || defaultIconClass);
58
+ const finalIconClass = cn(
59
+ variant === 'default' ? 'text-white' : themeIconColor,
60
+ iconClassName || defaultIconClass
61
+ );
46
62
 
47
63
  // set justify class according to alignment
48
64
  const getAlignmentClass = () => {
@@ -111,8 +127,9 @@ export function GradientButton({
111
127
  })();
112
128
 
113
129
  const shouldRenderIcon = iconNode !== null && iconNode !== undefined;
130
+ const iconPosition = iconForcePosition ?? (onClick ? 'left' : 'right');
114
131
 
115
- const buttonContent = onClick ? (
132
+ const buttonContent = iconPosition === 'left' ? (
116
133
  <>
117
134
  {shouldRenderIcon ? <span>{iconNode}</span> : null}
118
135
  <span className={cn(shouldRenderIcon && 'ml-1')}>{displayTitle}</span>
@@ -133,10 +150,29 @@ export function GradientButton({
133
150
  // Base styles extracted from Button component + size="lg" (h-11 px-8)
134
151
  // Removed [&_svg] constraints
135
152
  const baseButtonStyles = "inline-flex items-center gap-2 whitespace-nowrap h-11 px-8 ring-offset-background focus-visible:outline-hidden focus-visible:ring-2 focus-visible:ring-ring focus-visible:ring-offset-2 disabled:pointer-events-none disabled:opacity-50";
153
+ const variantClassName = variant === 'soft'
154
+ ? cn(
155
+ themeBgColor,
156
+ themeIconColor,
157
+ themeBorderColor,
158
+ 'border shadow-sm hover:shadow-md hover:brightness-95'
159
+ )
160
+ : variant === 'subtle'
161
+ ? cn(
162
+ themeMainBgColor,
163
+ themeIconColor,
164
+ 'border border-neutral-200 shadow-sm hover:shadow-md hover:bg-neutral-50 dark:border-neutral-800 dark:hover:bg-neutral-800'
165
+ )
166
+ : cn(
167
+ themeButtonGradientClass,
168
+ themeButtonGradientHoverClass,
169
+ 'text-white shadow-lg hover:shadow-xl'
170
+ );
136
171
 
137
172
  const buttonClassName = cn(
138
173
  baseButtonStyles,
139
- themeButtonGradientClass, themeButtonGradientHoverClass, 'text-white text-base font-bold shadow-lg hover:shadow-xl transition-all duration-300 rounded-full',
174
+ variantClassName,
175
+ 'text-base font-bold transition-all duration-300 rounded-full',
140
176
  alignmentClass,
141
177
  isDisabled && 'opacity-50 cursor-not-allowed',
142
178
  className,
package/src/main/index.ts CHANGED
@@ -6,6 +6,7 @@ export * from './loading';
6
6
  export * from './nprogress-bar';
7
7
  export * from './ads-alert-dialog';
8
8
  export * from './x-button'
9
+ export * from './x-toggle-button'
9
10
  export * from './ai-prompt-textarea'
10
11
  export * from './rich-text-expert'
11
12
  export * from './faq-interactive'
@@ -13,6 +14,7 @@ export * from './price-plan-interactive'
13
14
  export * from './gallery/gallery-interactive'
14
15
  export * from './delayed-img'
15
16
  export * from './snake-loading-frame'
17
+ export * from './pill-select'
16
18
  // Money Price Client Components
17
19
  export { MoneyPriceInteractive } from './money-price/money-price-interactive';
18
20
  export { MoneyPriceButton } from './money-price/money-price-button';
@@ -0,0 +1,4 @@
1
+ export { XPillSelect, type XPillOption, type XPillSelectProps } from './x-pill-select';
2
+ export { XFilterPills } from './x-filter-pills';
3
+ export { XFormPills } from './x-form-pills';
4
+ export { XTokenInput } from './x-token-input';
@@ -0,0 +1,36 @@
1
+ 'use client';
2
+
3
+ import { cn } from '@windrun-huaiin/lib/utils';
4
+ import { XPillSelect, type XPillOption } from './x-pill-select';
5
+
6
+ type XFilterPillsProps = {
7
+ label: string;
8
+ value: string;
9
+ options: XPillOption[];
10
+ onChange: (value: string) => void;
11
+ allLabel: string;
12
+ className?: string;
13
+ };
14
+
15
+ export function XFilterPills({
16
+ label,
17
+ value,
18
+ options,
19
+ onChange,
20
+ allLabel,
21
+ className,
22
+ }: XFilterPillsProps) {
23
+ return (
24
+ <div className={cn('space-y-1.5', className)}>
25
+ <div className="text-xs font-medium text-slate-700 dark:text-slate-200">{label}</div>
26
+ <XPillSelect
27
+ mode="single"
28
+ value={value}
29
+ onChange={onChange}
30
+ options={[{ label: allLabel, value: '' }, ...options]}
31
+ size="compact"
32
+ maxPillWidthClassName="max-w-[150px] sm:max-w-[220px]"
33
+ />
34
+ </div>
35
+ );
36
+ }
@@ -0,0 +1,39 @@
1
+ 'use client';
2
+
3
+ import { cn } from '@windrun-huaiin/lib/utils';
4
+ import { XPillSelect, type XPillOption } from './x-pill-select';
5
+
6
+ type XFormPillsProps = {
7
+ label: React.ReactNode;
8
+ value: string;
9
+ options: XPillOption[];
10
+ onChange: (value: string) => void;
11
+ emptyLabel: string;
12
+ allowClear?: boolean;
13
+ className?: string;
14
+ };
15
+
16
+ export function XFormPills({
17
+ label,
18
+ value,
19
+ options,
20
+ onChange,
21
+ emptyLabel,
22
+ allowClear = false,
23
+ className,
24
+ }: XFormPillsProps) {
25
+ return (
26
+ <div className={cn('space-y-2 text-sm', className)}>
27
+ <div className="font-medium text-slate-700 dark:text-slate-200">{label}</div>
28
+ <XPillSelect
29
+ mode="single"
30
+ value={value}
31
+ onChange={onChange}
32
+ options={options}
33
+ emptyLabel={emptyLabel}
34
+ allowClear={allowClear}
35
+ maxPillWidthClassName="max-w-[150px] sm:max-w-[220px]"
36
+ />
37
+ </div>
38
+ );
39
+ }