diff --git a/apps/web/package.json b/apps/web/package.json index fe0b239..59fbe2e 100644 --- a/apps/web/package.json +++ b/apps/web/package.json @@ -15,6 +15,7 @@ "@repo/ui": "workspace:*", "@repo/utils": "workspace:*", "@tailwindcss/vite": "^4.1.18", + "dayjs": "^1.11.19", "react": "^19.2.3", "react-dom": "^19.2.3", "react-router-dom": "^7.11.0", diff --git a/apps/web/src/apps/modules/example/showcase/components/switch.showcase.tsx b/apps/web/src/apps/modules/example/showcase/components/switch.showcase.tsx new file mode 100644 index 0000000..7f3e825 --- /dev/null +++ b/apps/web/src/apps/modules/example/showcase/components/switch.showcase.tsx @@ -0,0 +1,220 @@ +import React, { useState } from 'react'; +import { Switch } from '@repo/ui'; + +export const SwitchShowcase = () => { + // State untuk Controlled Switch Demo + const [checked, setChecked] = useState(false); + const [loading, setLoading] = useState(false); + + return ( +
+
+ {/* Header */} +
+

Switch Component

+

Showcase fitur, variant, status, dan state interaksi.

+
+ + {/* 1. VARIANTS */} +
+

1. Variants

+
+
+ {/* Variant: Outlined (Default) */} +
+

Outlined (Default)

+

Background transparan saat off.

+
+ + +
+
+ + {/* Variant: Filled */} +
+

Filled

+

Background abu-abu solid saat off.

+
+ + +
+
+
+
+
+ + {/* 2. STATUS COLORS */} +
+

2. Status Colors

+

+ Warna diterapkan pada state Checked dan Focus Ring. +

+ +
+
+
+ + Default (Brand) +
+ +
+ + Success +
+ +
+ + Warning +
+ +
+ + Error +
+ +
+ + Info +
+
+
+ +
+
+
+ + Default (Brand) +
+ +
+ + Success +
+ +
+ + Warning +
+ +
+ + Error +
+ +
+ + Info +
+
+
+
+ + {/* 3. STATES (Loading & Disabled) */} +
+

3. States

+
+ {/* Disabled State */} +
+

Disabled

+
+ + +
+
+ +
+ + {/* Loading State */} +
+

Loading

+
+ + + {/* Loading with Status Color */} + +
+
+
+
+ + {/* 4. CUSTOM SIZES */} +
+

4. Custom Sizes

+

Menggunakan CSS Variables inline untuk override ukuran default.

+
+ {/* Small Override */} +
+ + Tiny +
+ + {/* Normal */} +
+ + Default +
+ + {/* Large Override */} +
+ + Large +
+
+
+ + {/* 5. INTERACTIVE PLAYGROUND */} +
+

5. Interactive Playground

+
+
+
+

+ Value: {checked ? 'true' : 'false'} +

+

+ Loading: {loading ? 'true' : 'false'} +

+
+ + +
+ +
+ setChecked(v)} + loading={loading} + label="Control Me" + status="success" + variant="filled" + /> +
+
+
+
+
+ ); +}; diff --git a/apps/web/src/apps/modules/example/showcase/showcase.tsx b/apps/web/src/apps/modules/example/showcase/showcase.tsx index 452d00a..dd0c46a 100644 --- a/apps/web/src/apps/modules/example/showcase/showcase.tsx +++ b/apps/web/src/apps/modules/example/showcase/showcase.tsx @@ -2,6 +2,7 @@ import { useState } from 'react'; import { InputStatusType } from '@repo/ui'; import CheckboxShowcase from './components/checkbox.showcase'; import InputShowCase from './components/input.showcase'; +import { SwitchShowcase } from './components/switch.showcase'; export default function Showcase() { // State untuk menyimpan status yang dipilih @@ -65,6 +66,7 @@ export default function Showcase() {
+
diff --git a/packages/ui/package.json b/packages/ui/package.json index 6799f43..5f6d5fe 100644 --- a/packages/ui/package.json +++ b/packages/ui/package.json @@ -16,9 +16,12 @@ "@rc-component/form": "^1.6.2", "@rc-component/input": "^1.1.2", "@rc-component/input-number": "^1.6.2", + "@rc-component/picker": "^1.9.0", + "@rc-component/switch": "^1.0.3", "@rc-component/textarea": "^1.1.2", "@repo/utils": "workspace:*", "@tailwindcss/vite": "^4.1.18", + "dayjs": "^1.11.19", "react": "^19.2.3", "react-dom": "^19.2.3", "tailwind-merge": "^3.4.0", diff --git a/packages/ui/src/components/forms/index.ts b/packages/ui/src/components/forms/index.ts index b237281..f0b3015 100644 --- a/packages/ui/src/components/forms/index.ts +++ b/packages/ui/src/components/forms/index.ts @@ -8,3 +8,4 @@ export * from './input/input-number.component'; export * from './textarea/textarea.component'; export * from './checkbox/checkbox.component'; +export * from './switch/switch.component'; diff --git a/packages/ui/src/components/forms/styles/form.style.css b/packages/ui/src/components/forms/styles/form.style.css index 9ee07c8..5ebcca3 100644 --- a/packages/ui/src/components/forms/styles/form.style.css +++ b/packages/ui/src/components/forms/styles/form.style.css @@ -3,3 +3,4 @@ @import './input-number.style.css'; @import './textarea.style.css'; @import './checkbox.style.css'; +@import './switch.style.css'; diff --git a/packages/ui/src/components/forms/styles/switch.style.css b/packages/ui/src/components/forms/styles/switch.style.css new file mode 100644 index 0000000..32b8610 --- /dev/null +++ b/packages/ui/src/components/forms/styles/switch.style.css @@ -0,0 +1,443 @@ +@layer components { + /* ========================================= + BASE WRAPPER & LABEL + ========================================= */ + .rc-switch-wrapper { + display: inline-flex; + align-items: center; + cursor: pointer; + font-size: var(--form-label-font-size); + font-weight: var(--form-label-font-weight); + color: var(--form-label-color); + line-height: 1; + gap: 8px; /* Distance between switch and label */ + transition: all 0.2s; + vertical-align: middle; + } + + .rc-switch-wrapper-disabled { + cursor: not-allowed; + color: var(--disabled-text); + } + + .rc-switch-label-text { + line-height: var(--switch-height); /* Align text vertically with switch */ + font-size: var(--form-label-font-size); + font-weight: var(--form-label-font-weight); + color: var(--form-label-color); + } + + /* Container for relative positioning of loading state */ + .rc-switch-container { + position: relative; + line-height: 0; + } + + /* ========================================= + CORE SWITCH STRUCTURE + ========================================= */ + .rc-switch { + position: relative; + display: inline-block; + box-sizing: border-box; + width: var(--switch-width); + height: var(--switch-height); + line-height: calc(var(--switch-height) - 2px); + padding: 0; + vertical-align: middle; + border-radius: 9999px; /* Pill shape */ + border: 1px solid; /* Border color defined in variants */ + background-color: transparent; /* Bg defined in variants */ + cursor: pointer; + transition: all 0.3s cubic-bezier(0.35, 0, 0.25, 1); + overflow: visible; /* Changed to visible for focus rings or overflow effects if needed */ + } + + /* Focus Ring (Consistent with Checkbox) */ + .rc-switch:focus-visible, + .rc-switch:focus { + outline: none; + box-shadow: 0 0 0 3px var(--focus-ring-color); + border-color: var(--focus-border-color); + } + + /* ========================================= + HANDLE (THE CIRCLE) + ========================================= */ + .rc-switch:after { + position: absolute; + content: ' '; + top: 1px; /* (Height - Handle) / 2 approx, adjusted for border */ + left: var(--switch-padding); + width: var(--switch-handle-size); + height: var(--switch-handle-size); + border-radius: 50%; + background-color: #ffffff; + box-shadow: 0 2px 4px 0 rgba(0, 35, 11, 0.2); + transform: scale(1); + transition: all 0.3s cubic-bezier(0.35, 0, 0.25, 1); + cursor: pointer; + } + + /* Hover Effect on Handle */ + .rc-switch:hover:after { + transform: scale(1.1); + } + + .rc-switch:active:after { + transform: scale(1); /* Reset on click */ + width: calc(var(--switch-handle-size) + 4px); /* Stretch effect like iOS */ + } + + /* ========================================= + CHECKED STATE + ========================================= */ + .rc-switch-checked:after { + left: var(--switch-checked-pos); + } + + .rc-switch-checked:active:after { + left: calc(var(--switch-checked-pos) - 4px); /* Adjust stretch position */ + } + + /* ========================================= + INNER TEXT (ON/OFF LABELS) + ========================================= */ + .rc-switch-inner { + display: block; + margin: 0 26px 0 8px; /* Adjust spacing */ + color: #fff; + font-size: 12px; + transition: margin 0.3s cubic-bezier(0.35, 0, 0.25, 1); + pointer-events: none; + } + + .rc-switch-checked .rc-switch-inner { + margin: 0 8px 0 26px; + } + + /* ========================================= + LOADING STATE + ========================================= */ + .rc-switch-loading { + opacity: 0.7; + } + + /* The SVG Icon inside the handle */ + .rc-switch-loading-icon { + display: inline-block; + vertical-align: middle; + width: 12px; + height: 12px; + color: var(--color-brand-500); /* Loading icon color */ + animation: rcSwitchLoading 1s infinite linear; + /* Center inside the handle */ + position: absolute; + top: 50%; + left: 50%; + transform: translate(-50%, -50%); + z-index: 1; + } + + /* Override handle style when loading */ + .rc-switch-loading .rc-switch:after { + background-color: #fff; /* Ensure handle is white */ + } + + @keyframes rcSwitchLoading { + 100% { + transform: translate(-50%, -50%) rotate(360deg); + } + } + + /* ========================================= + VARIANTS & STATUS MATRIX + ========================================= */ + + /* ------------------------------- + VARIANT: OUTLINED (Default) + Looks like an empty input when off. + ------------------------------- */ + .switch-variant-outlined .rc-switch { + background-color: var(--color-gray-200); + border-color: var(--color-gray-200); + } + + .switch-variant-outlined .rc-switch:hover { + border-color: var(--color-brand-500); + } + + /* ------------------------------- + VARIANT: FILLED + Looks like a standard grey toggle when off. + ------------------------------- */ + .switch-variant-filled .rc-switch { + background-color: var(--color-gray-200); + border-color: var(--color-gray-200); + } + + .switch-variant-filled .rc-switch:hover { + border-color: var(--color-brand-500); + } + + /* ========================================= + STATUS COLORS (Applied to Checked State) + ========================================= */ + + /* --- DEFAULT (Brand) --- */ + + .switch-status-default .rc-switch-checked { + border-color: var(--color-brand-500); + background-color: var(--color-brand-500); + } + .switch-status-default .rc-switch:focus-visible, + .switch-status-default .rc-switch:focus { + box-shadow: 0 0 0 3px var(--color-brand-100); + border-color: var(--color-brand-500); + } + + /* --- ERROR --- */ + /* Hover Off state (Optional: Tint border red on hover even if off) */ + .switch-status-error.switch-variant-outlined .rc-switch { + background-color: var(--input-bg); + border-color: var(--color-error-300); + } + + .switch-status-error.switch-variant-outlined .rc-switch:hover { + border-color: var(--color-error-500); + } + + .switch-status-error.switch-variant-outlined .rc-switch:after { + background-color: var(--color-error-300); + box-shadow: 0 2px 4px 0 var(--color-error-100); + } + + .switch-status-error.switch-variant-filled .rc-switch { + background-color: var(--color-error-50); + border-color: var(--color-error-300); + } + + .switch-status-error.switch-variant-filled .rc-switch:hover { + border-color: var(--color-error-500); + } + + .switch-status-error.switch-variant-filled .rc-switch:after { + background-color: #fff; + } + + /* Checked State */ + .switch-status-error.switch-variant-outlined .rc-switch-checked { + border-color: var(--color-error-500); + background-color: var(--color-error-500); + } + .switch-status-error.switch-variant-outlined .rc-switch-checked:after { + background-color: #fff; + box-shadow: 0 2px 4px 0 rgba(0, 35, 11, 0.2); + } + + .switch-status-error.switch-variant-filled .rc-switch-checked { + border-color: var(--color-error-500); + background-color: var(--color-error-500); + } + + /* Focus */ + .switch-status-error .rc-switch:focus-visible, + .switch-status-error .rc-switch:focus { + box-shadow: 0 0 0 3px var(--color-error-100); + border-color: var(--color-error-500); + } + /* Loading Icon Color */ + .switch-status-error .rc-switch-loading-icon { + color: var(--color-error-500); + } + + /* --- WARNING --- */ + .switch-status-warning.switch-variant-outlined .rc-switch { + background-color: var(--input-bg); + border-color: var(--color-warning-300); + } + + .switch-status-warning.switch-variant-outlined .rc-switch:hover { + border-color: var(--color-warning-500); + } + + .switch-status-warning.switch-variant-outlined .rc-switch:after { + background-color: var(--color-warning-300); + box-shadow: 0 2px 4px 0 var(--color-warning-100); + } + + .switch-status-warning.switch-variant-filled .rc-switch { + background-color: var(--color-warning-50); + border-color: var(--color-warning-300); + } + + .switch-status-warning.switch-variant-filled .rc-switch:hover { + border-color: var(--color-warning-500); + } + + .switch-status-warning.switch-variant-filled .rc-switch:after { + background-color: #fff; + } + + /* Checked State */ + .switch-status-warning.switch-variant-outlined .rc-switch-checked { + border-color: var(--color-warning-500); + background-color: var(--color-warning-500); + } + .switch-status-warning.switch-variant-outlined .rc-switch-checked:after { + background-color: #fff; + box-shadow: 0 2px 4px 0 rgba(0, 35, 11, 0.2); + } + + .switch-status-warning.switch-variant-filled .rc-switch-checked { + border-color: var(--color-warning-500); + background-color: var(--color-warning-500); + } + + /* Focus */ + .switch-status-warning .rc-switch:focus-visible, + .switch-status-warning .rc-switch:focus { + box-shadow: 0 0 0 3px var(--color-warning-100); + border-color: var(--color-warning-500); + } + /* Loading Icon Color */ + .switch-status-warning .rc-switch-loading-icon { + color: var(--color-warning-500); + } + + /* --- SUCCESS --- */ + .switch-status-success.switch-variant-outlined .rc-switch { + background-color: var(--input-bg); + border-color: var(--color-success-300); + } + + .switch-status-success.switch-variant-outlined .rc-switch:hover { + border-color: var(--color-success-500); + } + + .switch-status-success.switch-variant-outlined .rc-switch:after { + background-color: var(--color-success-300); + box-shadow: 0 2px 4px 0 var(--color-success-100); + } + + .switch-status-success.switch-variant-filled .rc-switch { + background-color: var(--color-success-50); + border-color: var(--color-success-300); + } + + .switch-status-success.switch-variant-filled .rc-switch:hover { + border-color: var(--color-success-500); + } + + .switch-status-success.switch-variant-filled .rc-switch:after { + background-color: #fff; + } + + /* Checked State */ + .switch-status-success.switch-variant-outlined .rc-switch-checked { + border-color: var(--color-success-500); + background-color: var(--color-success-500); + } + .switch-status-success.switch-variant-outlined .rc-switch-checked:after { + background-color: #fff; + box-shadow: 0 2px 4px 0 rgba(0, 35, 11, 0.2); + } + + .switch-status-success.switch-variant-filled .rc-switch-checked { + border-color: var(--color-success-500); + background-color: var(--color-success-500); + } + + /* Focus */ + .switch-status-success .rc-switch:focus-visible, + .switch-status-success .rc-switch:focus { + box-shadow: 0 0 0 3px var(--color-success-100); + border-color: var(--color-success-500); + } + /* Loading Icon Color */ + .switch-status-success .rc-switch-loading-icon { + color: var(--color-success-500); + } + + /* --- INFO --- */ + .switch-status-info.switch-variant-outlined .rc-switch { + background-color: var(--input-bg); + border-color: var(--color-info-300); + } + + .switch-status-info.switch-variant-outlined .rc-switch:hover { + border-color: var(--color-info-500); + } + + .switch-status-info.switch-variant-outlined .rc-switch:after { + background-color: var(--color-info-300); + box-shadow: 0 2px 4px 0 var(--color-info-100); + } + + .switch-status-info.switch-variant-filled .rc-switch { + background-color: var(--color-info-50); + border-color: var(--color-info-300); + } + + .switch-status-info.switch-variant-filled .rc-switch:hover { + border-color: var(--color-info-500); + } + + .switch-status-info.switch-variant-filled .rc-switch:after { + background-color: #fff; + } + + /* Checked State */ + .switch-status-info.switch-variant-outlined .rc-switch-checked { + border-color: var(--color-info-500); + background-color: var(--color-info-500); + } + .switch-status-info.switch-variant-outlined .rc-switch-checked:after { + background-color: #fff; + box-shadow: 0 2px 4px 0 rgba(0, 35, 11, 0.2); + } + + .switch-status-info.switch-variant-filled .rc-switch-checked { + border-color: var(--color-info-500); + background-color: var(--color-info-500); + } + + /* Focus */ + .switch-status-info .rc-switch:focus-visible, + .switch-status-info .rc-switch:focus { + box-shadow: 0 0 0 3px var(--color-info-100); + border-color: var(--color-info-500); + } + /* Loading Icon Color */ + .switch-status-info .rc-switch-loading-icon { + color: var(--color-info-500); + } + + /* ========================================= + DISABLED STATE + ========================================= */ + .rc-switch-disabled, + .rc-switch-wrapper-disabled .rc-switch { + cursor: not-allowed; + opacity: 0.6; + background-color: var(--disabled-bg) !important; + border-color: var(--disabled-border) !important; + } + + .rc-switch-disabled:after, + .rc-switch-wrapper-disabled .rc-switch:after { + cursor: not-allowed; + background-color: #f9fafb; /* Lighter white/gray for disabled knob */ + } + + /* If checked and disabled */ + .rc-switch-disabled.rc-switch-checked { + background-color: var(--disabled-border) !important; /* Darker gray to show it is "on" but disabled */ + } + + /* Disable animations/hovers */ + .rc-switch-disabled:hover:after { + transform: scale(1); + animation-name: none; + } +} diff --git a/packages/ui/src/components/forms/switch/switch.component.tsx b/packages/ui/src/components/forms/switch/switch.component.tsx new file mode 100644 index 0000000..f45b23c --- /dev/null +++ b/packages/ui/src/components/forms/switch/switch.component.tsx @@ -0,0 +1,65 @@ +import { forwardRef } from 'react'; +import RcSwitch from '@rc-component/switch'; +import { SwitchProps } from '../types'; + +/** + * Small Spinner Component (SVG) + */ +const LoadingSpinner = () => ( + +); + +export const Switch = forwardRef((props, ref) => { + const { + label, + status = 'default', + variant = 'outlined', + className, + children, + style, + loading, + disabled, + ...rest + } = props; + + const displayLabel = label || children; + + const isEnabled = !disabled && !loading; + + const wrapperClass = [ + 'rc-switch-wrapper', + `switch-status-${status}`, + `switch-variant-${variant}`, + !isEnabled ? 'rc-switch-wrapper-disabled' : '', + className, + ] + .filter(Boolean) + .join(' '); + + return ( + + ); +}); + +Switch.displayName = 'Switch'; diff --git a/packages/ui/src/components/forms/types/index.ts b/packages/ui/src/components/forms/types/index.ts index 49e3508..0d30164 100644 --- a/packages/ui/src/components/forms/types/index.ts +++ b/packages/ui/src/components/forms/types/index.ts @@ -1,6 +1,6 @@ import type { FormProps as RcFormProps } from '@rc-component/form'; import type { Rule } from '@rc-component/form/lib/interface'; -import { ReactNode, ReactElement } from 'react'; +import { ReactNode, ReactElement, ComponentProps, CSSProperties } from 'react'; import { InputProps as RcInputProps } from '@rc-component/input'; import { TextAreaProps as RcTextAreaProps } from '@rc-component/textarea'; @@ -8,6 +8,9 @@ import { InputNumberProps as RcInputNumberProps } from '@rc-component/input-numb import { CheckboxProps as RcCheckboxProps } from '@rc-component/checkbox'; +import RcSwitch from '@rc-component/switch'; +type RcSwitchProps = ComponentProps; + /** * Define possible input statuses */ @@ -74,3 +77,11 @@ export interface TextAreaProps extends RcTextAreaProps, BaseFormInputComponentPr export interface CheckboxProps extends RcCheckboxProps, BaseFormInputComponentProps { label?: ReactNode; } + +/** + * Define Switch props + */ +export interface SwitchProps extends RcSwitchProps, BaseFormInputComponentProps { + label?: ReactNode; + loading?: boolean; +} diff --git a/packages/ui/src/globals.css b/packages/ui/src/globals.css index daf24c7..258259e 100644 --- a/packages/ui/src/globals.css +++ b/packages/ui/src/globals.css @@ -156,6 +156,15 @@ --disabled-bg: #f3f4f6; --disabled-text: var(--color-gray-400); --disabled-border: #e5e7eb; + + /* SWITCH COMPONENT VARIABLES */ + --switch-width: 44px; + --switch-height: 22px; + --switch-padding: 2px; /* Distance between handle and edge */ + + /* Calculate the handle position when checked */ + /* Formula: Width - HandleSize - Padding */ + --switch-checked-pos: calc(var(--switch-width) - var(--switch-handle-size) - var(--switch-padding)); } /* ========================================= diff --git a/pnpm-lock.yaml b/pnpm-lock.yaml index efc48e0..1e05bbf 100644 --- a/pnpm-lock.yaml +++ b/pnpm-lock.yaml @@ -78,6 +78,9 @@ importers: '@tailwindcss/vite': specifier: ^4.1.18 version: 4.1.18(vite@5.4.17) + dayjs: + specifier: ^1.11.19 + version: 1.11.19 react: specifier: ^19.2.3 version: 19.2.3 @@ -170,6 +173,12 @@ importers: '@rc-component/input-number': specifier: ^1.6.2 version: 1.6.2(react-dom@19.2.3)(react@19.2.3) + '@rc-component/picker': + specifier: ^1.9.0 + version: 1.9.0(dayjs@1.11.19)(react-dom@19.2.3)(react@19.2.3) + '@rc-component/switch': + specifier: ^1.0.3 + version: 1.0.3(react-dom@19.2.3)(react@19.2.3) '@rc-component/textarea': specifier: ^1.1.2 version: 1.1.2(react-dom@19.2.3)(react@19.2.3) @@ -179,6 +188,9 @@ importers: '@tailwindcss/vite': specifier: ^4.1.18 version: 4.1.18(vite@5.4.17) + dayjs: + specifier: ^1.11.19 + version: 1.11.19 react: specifier: ^19.2.3 version: 19.2.3 @@ -1206,6 +1218,75 @@ packages: '@babel/runtime': 7.28.4 dev: false + /@rc-component/motion@1.2.0(react-dom@19.2.3)(react@19.2.3): + resolution: {integrity: sha512-Vx+OL3I1l3HWflc1miXgjeFR9OnStKD8FOMLJCdby3I6HAOi8jo7of7iqF4hqvxQhoP31RTlNk+C+v5QjytAVg==} + peerDependencies: + react: '>=16.9.0' + react-dom: '>=16.9.0' + dependencies: + '@rc-component/util': 1.7.0(react-dom@19.2.3)(react@19.2.3) + clsx: 2.1.1 + react: 19.2.3 + react-dom: 19.2.3(react@19.2.3) + dev: false + + /@rc-component/overflow@1.0.0(react-dom@19.2.3)(react@19.2.3): + resolution: {integrity: sha512-GSlBeoE0XTBi5cf3zl8Qh7Uqhn7v8RrlJ8ajeVpEkNe94HWy5l5BQ0Mwn2TVUq9gdgbfEMUmTX7tJFAg7mz0Rw==} + peerDependencies: + react: '>=16.9.0' + react-dom: '>=16.9.0' + dependencies: + '@babel/runtime': 7.28.4 + '@rc-component/resize-observer': 1.1.1(react-dom@19.2.3)(react@19.2.3) + '@rc-component/util': 1.7.0(react-dom@19.2.3)(react@19.2.3) + clsx: 2.1.1 + react: 19.2.3 + react-dom: 19.2.3(react@19.2.3) + dev: false + + /@rc-component/picker@1.9.0(dayjs@1.11.19)(react-dom@19.2.3)(react@19.2.3): + resolution: {integrity: sha512-OLisdk8AWVCG9goBU1dWzuH5QlBQk8jktmQ6p0/IyBFwdKGwyIZOSjnBYo8hooHiTdl0lU+wGf/OfMtVBw02KQ==} + engines: {node: '>=12.x'} + peerDependencies: + date-fns: '>= 2.x' + dayjs: '>= 1.x' + luxon: '>= 3.x' + moment: '>= 2.x' + react: '>=16.9.0' + react-dom: '>=16.9.0' + peerDependenciesMeta: + date-fns: + optional: true + dayjs: + optional: true + luxon: + optional: true + moment: + optional: true + dependencies: + '@rc-component/overflow': 1.0.0(react-dom@19.2.3)(react@19.2.3) + '@rc-component/resize-observer': 1.1.1(react-dom@19.2.3)(react@19.2.3) + '@rc-component/trigger': 3.9.0(react-dom@19.2.3)(react@19.2.3) + '@rc-component/util': 1.7.0(react-dom@19.2.3)(react@19.2.3) + clsx: 2.1.1 + dayjs: 1.11.19 + react: 19.2.3 + react-dom: 19.2.3(react@19.2.3) + dev: false + + /@rc-component/portal@2.2.0(react-dom@19.2.3)(react@19.2.3): + resolution: {integrity: sha512-oc6FlA+uXCMiwArHsJyHcIkX4q6uKyndrPol2eWX8YPkAnztHOPsFIRtmWG4BMlGE5h7YIRE3NiaJ5VS8Lb1QQ==} + engines: {node: '>=12.x'} + peerDependencies: + react: '>=18.0.0' + react-dom: '>=18.0.0' + dependencies: + '@rc-component/util': 1.7.0(react-dom@19.2.3)(react@19.2.3) + clsx: 2.1.1 + react: 19.2.3 + react-dom: 19.2.3(react@19.2.3) + dev: false + /@rc-component/resize-observer@1.1.1(react-dom@19.2.3)(react@19.2.3): resolution: {integrity: sha512-NfXXMmiR+SmUuKE1NwJESzEUYUFWIDUn2uXpxCTOLwiRUUakd62DRNFjRJArgzyFW8S5rsL4aX5XlyIXyC/vRA==} peerDependencies: @@ -1217,6 +1298,18 @@ packages: react-dom: 19.2.3(react@19.2.3) dev: false + /@rc-component/switch@1.0.3(react-dom@19.2.3)(react@19.2.3): + resolution: {integrity: sha512-Jgi+EbOBquje/XNdofr7xbJQZPYJP+BlPfR0h+WN4zFkdtB2EWqEfvkXJWeipflwjWip0/17rNbxEAqs8hVHfw==} + peerDependencies: + react: '>=16.9.0' + react-dom: '>=16.9.0' + dependencies: + '@rc-component/util': 1.7.0(react-dom@19.2.3)(react@19.2.3) + clsx: 2.1.1 + react: 19.2.3 + react-dom: 19.2.3(react@19.2.3) + dev: false + /@rc-component/textarea@1.1.2(react-dom@19.2.3)(react@19.2.3): resolution: {integrity: sha512-9rMUEODWZDMovfScIEHXWlVZuPljZ2pd1LKNjslJVitn4SldEzq5vO1CL3yy3Dnib6zZal2r2DPtjy84VVpF6A==} peerDependencies: @@ -1231,6 +1324,22 @@ packages: react-dom: 19.2.3(react@19.2.3) dev: false + /@rc-component/trigger@3.9.0(react-dom@19.2.3)(react@19.2.3): + resolution: {integrity: sha512-X8btpwfrT27AgrZVOz4swclhEHTZcqaHeQMXXBgveagOiakTa36uObXbdwerXffgV8G9dH1fAAE0DHtVQs8EHg==} + engines: {node: '>=8.x'} + peerDependencies: + react: '>=18.0.0' + react-dom: '>=18.0.0' + dependencies: + '@rc-component/motion': 1.2.0(react-dom@19.2.3)(react@19.2.3) + '@rc-component/portal': 2.2.0(react-dom@19.2.3)(react@19.2.3) + '@rc-component/resize-observer': 1.1.1(react-dom@19.2.3)(react@19.2.3) + '@rc-component/util': 1.7.0(react-dom@19.2.3)(react@19.2.3) + clsx: 2.1.1 + react: 19.2.3 + react-dom: 19.2.3(react@19.2.3) + dev: false + /@rc-component/util@1.7.0(react-dom@19.2.3)(react@19.2.3): resolution: {integrity: sha512-tIvIGj4Vl6fsZFvWSkYw9sAfiCKUXMyhVz6kpKyZbwyZyRPqv2vxYZROdaO1VB4gqTNvUZFXh6i3APUiterw5g==} peerDependencies: