diff --git a/.storybook/preview.ts b/.storybook/preview.tsx
similarity index 72%
rename from .storybook/preview.ts
rename to .storybook/preview.tsx
index 31f371ea..b092d3ff 100644
--- a/.storybook/preview.ts
+++ b/.storybook/preview.tsx
@@ -1,6 +1,10 @@
+import React from 'react';
+
import type { Preview } from '@storybook/react-vite';
+
import '../src/styles/reset.scss';
import '../src/styles/defaults.scss';
+import { ToastContainer } from '../src/toast';
const preview: Preview = {
parameters: {
@@ -21,11 +25,20 @@ const preview: Preview = {
'Molecules',
'Layouts',
'Wrappers',
+ 'Extras',
'*',
],
},
},
},
+ decorators: [
+ (Story) => (
+
+
+
+
+ ),
+ ],
};
export default preview;
diff --git a/CHANGELOG.md b/CHANGELOG.md
index f4a0cd67..efd43090 100644
--- a/CHANGELOG.md
+++ b/CHANGELOG.md
@@ -8,8 +8,10 @@ The format is based on [Keep a Changelog](https://keepachangelog.com/en/1.0.0/)
## [Unreleased]
### Added
+- [MAJOR] Added `@kibalabs/ui-react/toast` (all of `@kibalabs/ui-react-toast`) and `@kibalabs/ui-react/dropzone` (all of `@kibalabs/ui-react-dropzone`) with their styles, `react-hot-toast` and `react-dropzone` are optional peer dependencies
### Changed
+- [MAJOR] Use `@kibalabs/core/react` instead of `@kibalabs/core-react`, `react-router` is now a peer dependency
- [MINOR] Correction for using `childSizeResponsive.base` size in `EqualGrid`
- [MINOR] Fix `Box` and `Stack` to not inherit sizing props from parent when not intended
diff --git a/README.md b/README.md
index e63f8a30..fb08d875 100644
--- a/README.md
+++ b/README.md
@@ -1,476 +1,72 @@
-# UI-React
+# @kibalabs/ui-react
-A React component library for building powerful, consistent applications at scale.
+Kiba Labs' React component library. Components only define layout; how they look comes from a global theme applied through variants.
-UI-React enforces a strong separation between **theming** and **layout**. This practice enables teams of all sizes to build beautiful, efficient, and consistent UIs quickly.
+Docs and live examples: [ui-react-docs.kibalabs.com](https://ui-react-docs.kibalabs.com)
-## Quick Start
-
-### Installation
+## Install
```bash
-npm install @kibalabs/ui-react
+npm install @kibalabs/ui-react @kibalabs/core react react-dom react-router
```
-### Basic Setup
-
-Wrap your app with `KibaApp` and import the CSS:
+## Setup
```tsx
-import React from 'react';
import { KibaApp } from '@kibalabs/ui-react';
-import '@kibalabs/ui-react/dist/index.css';
import './theme.scss';
-export const App = (): React.ReactElement => {
- return (
-
- {/* Your app content */}
-
- );
-};
+export const App = (): React.ReactElement => (
+ {/* ... */}
+);
```
-### Theme Configuration
-
-Create a `theme.scss` file to customize the look and feel:
-
```scss
-@use '@kibalabs/ui-react/styles/reset';
-@use '@kibalabs/ui-react/styles/colors';
-@use '@kibalabs/ui-react/styles/global';
+// theme.scss
+@use '@kibalabs/ui-react/styles.scss';
:root {
- // Colors
--kiba-color-background: #ffffff;
--kiba-color-brand-primary: #4b6cb7;
--kiba-color-text: #333333;
-
- // Typography
- --kiba-font-family: -apple-system, system-ui, sans-serif;
- --kiba-font-size: 16px;
-
- // Spacing & Borders
+ --kiba-font-family: system-ui, sans-serif;
--kiba-border-radius: 0.5em;
}
```
-That's it! You're ready to use UI-React components.
-
----
-
-## Documentation
+Use `@kibalabs/ui-react/styles.css` instead if you don't use scss.
-See live examples and detailed documentation in [the Storybook](https://ui-react-docs.kibalabs.com).
+## Entries
----
+| Import | Styles | Needs installed |
+| --- | --- | --- |
+| `@kibalabs/ui-react` | `styles.scss` / `styles.css` | - |
+| `@kibalabs/ui-react/toast` (was `@kibalabs/ui-react-toast`) | `toast/styles.scss` / `toast/styles.css` | `react-hot-toast` |
+| `@kibalabs/ui-react/dropzone` (was `@kibalabs/ui-react-dropzone`) | `dropzone/styles.scss` / `dropzone/styles.css` | `react-dropzone` |
-## Core Philosophy
+Toast and dropzone styles only hold their own rules, so use them on top of the main styles.
-### Separation of Theming and Layout
+## Theming
-UI-React is built around one core principle: **component code should only define layout, never appearance**.
-
-In traditional React development, styling is often mixed with component logic:
+- **Variables:** everything is themed with CSS variables named `--kiba-{category}-{name}` (e.g. `--kiba-color-brand-primary`, `--kiba-padding`). Each color also gets `-light10/25`, `-dark10/25` and `-clear25/50/75` variants.
+- **Variants:** every component takes a `variant` that becomes css classes, and hyphens combine them (`variant="primary-large"` → `.primary.large`). Style them in your theme, e.g. `.KibaButton.primary { ... }`.
+- **Layers:** styles are in `@layer kiba-reset, kiba-structure, kiba-theme`, so your theme overrides them without `!important`.
```tsx
-// ❌ Traditional approach - styling mixed with layout
-
-
Title
-
Content
-
-```
-
-With UI-React, components only specify **what** they are, not **how** they look:
-
-```tsx
-// ✅ UI-React approach - layout only, theming via variants
-
+
- Title
- Content
+ Title
+
```
-All visual styling is defined globally in SCSS and applied through **variants**.
-
-### Why This Matters
-
-1. **Consistency** - All buttons look like buttons, all cards look like cards. No one-off styles.
-2. **Maintainability** - Change your brand color once, it updates everywhere.
-3. **Speed** - Building new features is fast when you don't think about styling.
-4. **Reusability** - Components work in any context because they don't carry styling baggage.
-5. **Team Scaling** - Designers define the theme, developers use it. Clear separation of concerns.
-
----
-
-## Theming System
-
-UI-React uses CSS Custom Properties (CSS Variables) for all theming. This provides:
-
-- Runtime theme switching (light/dark mode)
-- No build step required for theme changes
-- Standard CSS cascade and specificity rules
-- Easy debugging in browser dev tools
-
-### CSS Variable Naming Convention
-
-All UI-React variables follow the pattern `--kiba-{category}-{name}`:
-
-```scss
-// Colors
---kiba-color-background
---kiba-color-brand-primary
---kiba-color-text
---kiba-color-error
---kiba-color-success
-
-// Typography
---kiba-font-family
---kiba-font-size
---kiba-line-height
-
-// Spacing
---kiba-padding
---kiba-padding-narrow
---kiba-padding-wide
-
-// Borders
---kiba-border-radius
---kiba-border-width
-```
-
-### Color Variants
-
-For each base color, UI-React automatically generates variants using CSS `color-mix()`:
-
-```scss
---kiba-color-brand-primary // Base color
---kiba-color-brand-primary-light10 // 10% lighter
---kiba-color-brand-primary-light25 // 25% lighter
---kiba-color-brand-primary-dark10 // 10% darker
---kiba-color-brand-primary-dark25 // 25% darker
---kiba-color-brand-primary-clear25 // 25% transparent
---kiba-color-brand-primary-clear50 // 50% transparent
---kiba-color-brand-primary-clear75 // 75% transparent
-```
-
-This means you only need to define base colors, and all variants are available automatically.
-
-### Component Variants
-
-Every component supports a `variant` prop that maps to CSS classes:
-
-```tsx
-
-
-
-```
-
-Define custom variants in your theme.scss:
-
-```scss
-.KibaButton {
- // Default button styles are inherited from ui-react
-
- &.primary {
- background-color: var(--kiba-color-brand-primary);
- color: var(--kiba-color-text-on-brand);
- }
-
- &.secondary {
- background-color: transparent;
- border: 1px solid var(--kiba-color-brand-primary);
- color: var(--kiba-color-brand-primary);
- }
-
- &.destructive {
- background-color: var(--kiba-color-error);
- color: white;
- }
-}
-```
-
-### Multi-Part Variants
-
-Variants can be combined using hyphens:
-
-```tsx
-
-Bold Header
-Styled Card
-```
-
-Each part becomes a separate CSS class, so `primary-large` applies both `.primary` and `.large`.
-
----
-
-## CSS Layers
-
-UI-React uses CSS `@layer` to organize styles with predictable specificity:
-
-```scss
-@layer kiba-reset, kiba-structure, kiba-theme;
-```
-
-1. **kiba-reset** - CSS reset and normalization
-2. **kiba-structure** - Component structure (display, flex, positioning)
-3. **kiba-theme** - Visual styling (colors, borders, shadows)
-
-This ensures your theme overrides always take precedence without needing `!important`.
-
----
-
-## Component Architecture
-
-### Particles
-
-The lowest-level building blocks. Pure visual elements with no semantic meaning:
-
-- `Box` - A container with optional styling
-- `Text` - Styled text content
-- `Icon` / `KibaIcon` - Icon display
-- `Image` / `Video` / `Media` - Media elements
-- `Divider` - Visual separator
-- `Spacing` - Whitespace control
-
-### Atoms
-
-Interactive elements that handle user input:
-
-- `Button` / `IconButton` - Clickable actions
-- `Link` / `LinkBase` - Navigation
-- `Checkbox` / `Switch` - Boolean inputs
-- `InputWrapper` - Form field wrapper
-- `Dialog` - Modal overlays
-- And more...
-
-### Molecules
-
-Composed components for common patterns:
-
-- `Form` - Form container with loading states
-- `SingleLineInput` / `MultiLineInput` - Text inputs
-- `OptionSelect` - Dropdown selection
-- `TabBar` - Navigation tabs
-- `Markdown` / `MarkdownText` - Rendered markdown
-- And more...
-
-### Layouts
-
-Components that control arrangement of children:
-
-- `Stack` - Flexbox-based linear layout
-- `Grid` - CSS Grid layout
-- `LayerContainer` - Stacked layers (z-axis)
-- `Container` - Max-width wrapper
-
-### Wrappers
-
-Components that modify their children without adding DOM elements:
-
-- `BackgroundView` - Adds background styling
-- `ColorSettingView` - Overrides color context
-- `PaddingView` - Adds padding
-- `HidingView` - Conditional visibility
-- `ResponsiveHidingView` - Breakpoint-based visibility
-
----
-
-## Responsive Design
-
-### Responsive Props
-
-Many components accept responsive prop objects:
-
-```tsx
-
- Item 1
- Item 2
-
-```
-
-This stacks vertically on mobile, horizontally on medium+ screens.
-
-### Screen Size Breakpoints
-
-```
-Base: 0px+
-Small: 576px+
-Medium: 768px+
-Large: 992px+
-ExtraLarge: 1200px+
-```
-
-### ResponsiveHidingView
-
-Control visibility at different breakpoints:
-
-```tsx
-
- Only visible on tablets and up
-
-
-
- Only visible on mobile
-
-```
-
----
-
-## Example Usage
-
-Here's a real-world example showing the separation of layout and theming:
-
-```tsx
-import React from 'react';
-import { Box, Text, Stack, Direction, KibaIcon, Alignment, Spacing } from '@kibalabs/ui-react';
-
-interface IMetaItemProps {
- isChecked: boolean;
- text: string;
-}
-
-const MetaItem = (props: IMetaItemProps): React.ReactElement => {
- return (
-
-
- {props.text}
-
- );
-};
-
-interface ICardProps {
- title: string;
- items: Array<{ text: string; isChecked: boolean }>;
-}
-
-export const MetaCard = (props: ICardProps): React.ReactElement => {
- return (
-
-
- {props.title}
- {props.items.map((item, index) => (
-
- ))}
-
-
- );
-};
-```
-
-Notice:
-- **No colors, spacing values, or visual styles in the component code**
-- Layout is explicit via `Stack` and `Direction`
-- Appearance is controlled entirely through variants (`card`, `header3`, `small`)
-- The component is completely reusable across any theme
-
----
-
-## Creating Custom Components
-
-When creating custom components in your project, extend `IComponentProps` and pass the styling props to your root element:
-
-```tsx
-import { IComponentProps, Stack, Text } from '@kibalabs/ui-react';
-
-interface IMyComponentProps extends IComponentProps {
- title: string;
- onClicked?: () => void;
-}
-
-export const MyComponent = (props: IMyComponentProps): React.ReactElement => {
- return (
-
- {props.title}
-
- );
-};
-```
-
-`IComponentProps` provides:
-- `id?: string` - HTML id attribute
-- `className?: string` - Additional CSS classes
-- `style?: React.CSSProperties` - Inline styles
-- `variant?: string` - Component variant (if applicable)
-
-**Always pass `id`, `className`, and `style` to your root element** to ensure consumers can style and identify your component.
-
----
-
## Development
-### Prerequisites
-
-- Node.js 18+
-- npm 9+
-
-### Setup
-
```bash
-# Install dependencies
-npm install
-
-# Start development mode with hot reloading
-npm run start-dev
-
-# Start Storybook documentation
-npm run docs
-```
-
-### Building
-
-```bash
-# Build the library
-make build
-
-# Run linting
-make lint-fix
-
-# Run type checking
+make install
+make lint-check
make type-check
+make build
+make start-docs # storybook
```
-
-### Using Local Version in Another Project
-
-```bash
-# In ui-react directory
-npm link
-
-# In your project directory
-npm link @kibalabs/ui-react
-```
-
----
-
-## Support
-
-UI-React is primarily maintained by [@krishan711](https://twitter.com/krishan711).
-
-For help with contributing or using UI-React in your project, feel free to reach out!
-
----
-
-## Projects Using UI-React
-
-- **[everypage](https://www.everypagehq.com)** - Website builder built as a thin layer on UI-React
-- **[everysize](https://everysize-app.kibalabs.com)** ([source](https://github.com/kibalabs/everysize-app)) - Multi-resolution website testing tool
-- **[Appage](https://www.appage.io)** - Mobile app landing page builder
-
----
-
-## License
-
-MIT
diff --git a/config.build.js b/config.build.js
new file mode 100644
index 00000000..cdfafb78
--- /dev/null
+++ b/config.build.js
@@ -0,0 +1,9 @@
+export default (config) => {
+ const newConfig = config;
+ newConfig.entries = {
+ index: './src/index.ts',
+ 'toast/index': './src/toast/index.ts',
+ 'dropzone/index': './src/dropzone/index.ts',
+ };
+ return newConfig;
+};
diff --git a/makefile b/makefile
index ac46f9a3..5ee2276c 100644
--- a/makefile
+++ b/makefile
@@ -30,7 +30,7 @@ security-check-ci:
@ echo "Not Supported"
build:
- @ NODE_ENV=production npx build-module-rolldown
+ @ NODE_ENV=production npx build-module-rolldown --config-modifier ./config.build.js
build-ssr:
@ echo "Not Supported"
@@ -42,10 +42,10 @@ build-docs:
@ npx storybook build --docs --output-dir dist
start:
- @ NODE_ENV=development npx build-module-rolldown --start
+ @ NODE_ENV=development npx build-module-rolldown --config-modifier ./config.build.js --start
start-prod:
- @ NODE_ENV=production npx build-module-rolldown --start
+ @ NODE_ENV=production npx build-module-rolldown --config-modifier ./config.build.js --start
start-docs:
@ npx storybook dev --docs --port 6006
diff --git a/package-lock.json b/package-lock.json
index 7de47f0f..5c48e711 100644
--- a/package-lock.json
+++ b/package-lock.json
@@ -9,25 +9,38 @@
"version": "0.12.0",
"license": "MIT",
"dependencies": {
- "@kibalabs/core": "^0.7.2-next.9",
- "@kibalabs/core-react": "^0.10.1-next.7",
+ "@kibalabs/core": "^0.7.2-next.10",
"lazysizes": "^5.3.2",
"markdown-to-jsx": "^9.10.3"
},
"devDependencies": {
- "@kibalabs/build": "0.14.2-next.14",
+ "@kibalabs/build": "0.14.2-next.16",
"@storybook/addon-docs": "10.6.4",
"@storybook/react-vite": "10.6.4",
"@types/react": "19.3.0",
"@types/react-dom": "19.3.0",
"react": "19.3.1",
"react-dom": "19.3.1",
+ "react-dropzone": "20.1.4",
+ "react-hot-toast": "2.6.1",
+ "react-router": "8.5.0",
"remark-gfm": "4.0.1",
"storybook": "10.6.4"
},
"peerDependencies": {
"react": "^19.0.0",
- "react-dom": "^19.0.0"
+ "react-dom": "^19.0.0",
+ "react-dropzone": "^20.1.4",
+ "react-hot-toast": "^2.6.1",
+ "react-router": "^8.5.0"
+ },
+ "peerDependenciesMeta": {
+ "react-dropzone": {
+ "optional": true
+ },
+ "react-hot-toast": {
+ "optional": true
+ }
}
},
"node_modules/@adobe/css-tools": {
@@ -1280,9 +1293,9 @@
"license": "MIT"
},
"node_modules/@kibalabs/build": {
- "version": "0.14.2-next.14",
- "resolved": "https://registry.npmjs.org/@kibalabs/build/-/build-0.14.2-next.14.tgz",
- "integrity": "sha512-ARSCLon/EGnDH6jdTJqvmodiClYNFzpt25jFHWzkNtVLihcivnJFWVp84VS8p9AeyyYOsv1BbZqxJO9s8AWscA==",
+ "version": "0.14.2-next.16",
+ "resolved": "https://registry.npmjs.org/@kibalabs/build/-/build-0.14.2-next.16.tgz",
+ "integrity": "sha512-Kqb8Ah6QL+X2wB6597G+OEeOQEC8ba7Iba7SnHTqxQZ6FwibrvDWzVQ2UOdj8bZZLP99Y/G9rUUTcTYt3HBcDg==",
"dev": true,
"license": "MIT",
"dependencies": {
@@ -1326,29 +1339,55 @@
}
},
"node_modules/@kibalabs/core": {
- "version": "0.7.2-next.9",
- "resolved": "https://registry.npmjs.org/@kibalabs/core/-/core-0.7.2-next.9.tgz",
- "integrity": "sha512-xnTr4y+sLeCeBg7w/o9NxHO/rz4ZONq+0pZ4eFjSS1/EJ3zQBA5mVL0FHpkcH+VOMify7xl/cigo0QkeX2lP6A==",
+ "version": "0.7.2-next.10",
+ "resolved": "https://registry.npmjs.org/@kibalabs/core/-/core-0.7.2-next.10.tgz",
+ "integrity": "sha512-cO+jgtcXO4GOJIsYCQNK21GsOLq5k6XhLhB04gf/bv/BtgrOO1pEQPrc7wvIE/YhfOB7ZJyt7IV/ZA7tgAhuyA==",
"license": "MIT",
"dependencies": {
"date-fns": "^4.4.0",
"date-fns-tz": "^3.2.0",
"deepmerge": "^4.3.1",
"fast-deep-equal": "^3.1.3"
- }
- },
- "node_modules/@kibalabs/core-react": {
- "version": "0.10.1-next.7",
- "resolved": "https://registry.npmjs.org/@kibalabs/core-react/-/core-react-0.10.1-next.7.tgz",
- "integrity": "sha512-7woi2KS5lK/EzIDauDLdcV4sXevOc4pyIP7dOHZ/L96p0EFsRYqzKH65dwTkm1fcsBnCwiHjtpL4NA2VPp9bzw==",
- "license": "MIT",
- "dependencies": {
- "@kibalabs/core": "^0.7.2-next.9",
- "react-is": "^19.3.1",
- "react-router": "^8.5.0"
},
"peerDependencies": {
- "react": "^19.0.0"
+ "@base-org/account": "^2.5.13",
+ "@reown/appkit": "^1.8.24",
+ "@reown/appkit-adapter-ethers": "^1.8.24",
+ "@safe-global/safe-apps-provider": "^0.18.6",
+ "@safe-global/safe-apps-sdk": "^9.1.0",
+ "ethers": "^6.17.0",
+ "react": "^19.0.0",
+ "react-dom": "^19.0.0",
+ "react-router": "^8.5.0"
+ },
+ "peerDependenciesMeta": {
+ "@base-org/account": {
+ "optional": true
+ },
+ "@reown/appkit": {
+ "optional": true
+ },
+ "@reown/appkit-adapter-ethers": {
+ "optional": true
+ },
+ "@safe-global/safe-apps-provider": {
+ "optional": true
+ },
+ "@safe-global/safe-apps-sdk": {
+ "optional": true
+ },
+ "ethers": {
+ "optional": true
+ },
+ "react": {
+ "optional": true
+ },
+ "react-dom": {
+ "optional": true
+ },
+ "react-router": {
+ "optional": true
+ }
}
},
"node_modules/@mdx-js/react": {
@@ -2444,6 +2483,7 @@
"version": "0.22.1",
"resolved": "https://registry.npmjs.org/@remix-run/route-pattern/-/route-pattern-0.22.1.tgz",
"integrity": "sha512-czdGJWh09Lapvcqt7Vb09KlrU2PhRJ8xQaI+AItTuD9aDJ5MAgxnS38lnys6Ll+6RJEqPiaUqTwIQhVLwFvv+w==",
+ "devOptional": true,
"license": "MIT"
},
"node_modules/@rolldown/binding-android-arm-eabi": {
@@ -4259,6 +4299,16 @@
"node": ">= 0.4"
}
},
+ "node_modules/attr-accept": {
+ "version": "4.0.1",
+ "resolved": "https://registry.npmjs.org/attr-accept/-/attr-accept-4.0.1.tgz",
+ "integrity": "sha512-rOKAGOwbnTUvwTL8rNA0hWnU3uX9tOI20di4KjR5I1ez/RJmnA37W3zz4EMxGC2YnI289yPjRy63CdAZeQFZ4Q==",
+ "dev": true,
+ "license": "MIT",
+ "engines": {
+ "node": ">= 22"
+ }
+ },
"node_modules/available-typed-arrays": {
"version": "1.0.7",
"resolved": "https://registry.npmjs.org/available-typed-arrays/-/available-typed-arrays-1.0.7.tgz",
@@ -4755,6 +4805,7 @@
"version": "3.1.1",
"resolved": "https://registry.npmjs.org/cookie-es/-/cookie-es-3.1.1.tgz",
"integrity": "sha512-UaXxwISYJPTr9hwQxMFYZ7kNhSXboMXP+Z3TRX6f1/NyaGPfuNUZOWP1pUEb75B2HjfklIYLVRfWiFZJyC6Npg==",
+ "devOptional": true,
"license": "MIT"
},
"node_modules/cookie-signature": {
@@ -6180,6 +6231,16 @@
"node": ">=16.0.0"
}
},
+ "node_modules/file-selector": {
+ "version": "5.0.1",
+ "resolved": "https://registry.npmjs.org/file-selector/-/file-selector-5.0.1.tgz",
+ "integrity": "sha512-v0g/PTeuQgvKCBrVRsfVudvwXlRHSWHEQkVgKawgCGHkEpKA1clp3Om5jvEVhz8G9W/mOYjJH9FhkH4C888PgQ==",
+ "dev": true,
+ "license": "MIT",
+ "engines": {
+ "node": ">= 22"
+ }
+ },
"node_modules/fill-range": {
"version": "7.1.1",
"resolved": "https://registry.npmjs.org/fill-range/-/fill-range-7.1.1.tgz",
@@ -6628,6 +6689,16 @@
"dev": true,
"license": "MIT"
},
+ "node_modules/goober": {
+ "version": "2.1.19",
+ "resolved": "https://registry.npmjs.org/goober/-/goober-2.1.19.tgz",
+ "integrity": "sha512-U7veizMqxyKlM58+Z5j2ngJBH/r9siDmxpvNxSw0PylF6WQvrASJEZrxh1hidRBJc2jqoBVSyOban5u8m+6Rxg==",
+ "dev": true,
+ "license": "MIT",
+ "peerDependencies": {
+ "csstype": "^3.0.10"
+ }
+ },
"node_modules/gopd": {
"version": "1.2.0",
"resolved": "https://registry.npmjs.org/gopd/-/gopd-1.2.0.tgz",
@@ -9860,6 +9931,7 @@
"version": "19.3.1",
"resolved": "https://registry.npmjs.org/react/-/react-19.3.1.tgz",
"integrity": "sha512-QNhWdt7nrgVWWQG58QuGsAR3jv3Hbe4mb4vz7w2csnHavciZJgda1CPNaldF6eVxv90ud3jUXpKlHL69gO38yw==",
+ "devOptional": true,
"license": "MIT",
"engines": {
"node": ">=0.10.0"
@@ -9923,16 +9995,62 @@
"react": "^19.3.1"
}
},
- "node_modules/react-is": {
- "version": "19.3.1",
- "resolved": "https://registry.npmjs.org/react-is/-/react-is-19.3.1.tgz",
- "integrity": "sha512-RRieF6IyxQBkcK6pP8xOHprLTPW6QjRkbGdImtqNme+/hYVwCZkLQLdlZGOhUqXwkS9IEynaGvPJtv6XB/cz0Q==",
- "license": "MIT"
+ "node_modules/react-dropzone": {
+ "version": "20.1.4",
+ "resolved": "https://registry.npmjs.org/react-dropzone/-/react-dropzone-20.1.4.tgz",
+ "integrity": "sha512-LyjT9iQySNkJGC6yL+XTlmfTRxHhPx0eSoTh+WlR0Ge+W35rLcRH/oH7w5bzijfPHeCFcLnO9G7i+hX+LINAAA==",
+ "dev": true,
+ "license": "MIT",
+ "dependencies": {
+ "attr-accept": "^4.0.0",
+ "file-selector": "^5.0.1"
+ },
+ "engines": {
+ "node": ">= 22"
+ },
+ "peerDependencies": {
+ "@types/react": "*",
+ "react": ">= 18"
+ },
+ "peerDependenciesMeta": {
+ "@types/react": {
+ "optional": true
+ }
+ }
+ },
+ "node_modules/react-hot-toast": {
+ "version": "2.6.1",
+ "resolved": "https://registry.npmjs.org/react-hot-toast/-/react-hot-toast-2.6.1.tgz",
+ "integrity": "sha512-gjFsf05dxcku0FkyMtFH+XmYFdA2odXfBVknEr/IZ+XpUjwsgvtY2616sOpUynK+l9ykQDRNpaJ1hYfuximUiA==",
+ "dev": true,
+ "license": "MIT",
+ "dependencies": {
+ "csstype": "^3.1.3",
+ "goober": "^2.1.16"
+ },
+ "engines": {
+ "node": ">=10"
+ },
+ "peerDependencies": {
+ "@types/react": "*",
+ "@types/react-dom": "*",
+ "react": ">=16",
+ "react-dom": ">=16"
+ },
+ "peerDependenciesMeta": {
+ "@types/react": {
+ "optional": true
+ },
+ "@types/react-dom": {
+ "optional": true
+ }
+ }
},
"node_modules/react-router": {
"version": "8.5.0",
"resolved": "https://registry.npmjs.org/react-router/-/react-router-8.5.0.tgz",
"integrity": "sha512-9nEd/deifcTJIIcUaNIyQGkyXD0D6QVB9XD2O5GgHpP3xu3U5RXm87YQ8++Wn8JQWgMBM/5+PjWPM/7n7O7WHA==",
+ "devOptional": true,
"license": "MIT",
"dependencies": {
"@remix-run/route-pattern": "^0.22.1",
diff --git a/package.json b/package.json
index 4c136fe0..25e4cf3a 100644
--- a/package.json
+++ b/package.json
@@ -1,7 +1,7 @@
{
"name": "@kibalabs/ui-react",
"version": "0.12.0",
- "description": "React UI component library for building projects at Kiba Labs",
+ "description": "React UI component library for building projects at Kiba Labs (with toasts and dropzones)",
"license": "MIT",
"repository": {
"type": "git",
@@ -19,10 +19,25 @@
"exports": {
".": {
"types": "./dist/index.d.ts",
- "import": "./dist/index.js"
+ "import": "./dist/index.js",
+ "default": "./dist/index.js"
+ },
+ "./toast": {
+ "types": "./dist/toast/index.d.ts",
+ "import": "./dist/toast/index.js",
+ "default": "./dist/toast/index.js"
+ },
+ "./dropzone": {
+ "types": "./dist/dropzone/index.d.ts",
+ "import": "./dist/dropzone/index.js",
+ "default": "./dist/dropzone/index.js"
},
"./styles.css": "./dist/index.css",
- "./styles.scss": "./src/styles/all.scss"
+ "./styles.scss": "./src/styles/all.scss",
+ "./toast/styles.css": "./dist/toast/index.css",
+ "./toast/styles.scss": "./src/toast/styles.scss",
+ "./dropzone/styles.css": "./dist/dropzone/index.css",
+ "./dropzone/styles.scss": "./src/dropzone/styles.scss"
},
"files": [
"dist/*",
@@ -31,27 +46,42 @@
"src/layouts/*/styles.scss",
"src/atoms/*/styles.scss",
"src/molecules/*/styles.scss",
- "src/wrappers/*/styles.scss"
+ "src/wrappers/*/styles.scss",
+ "src/toast/styles.scss",
+ "src/dropzone/styles.scss"
],
"dependencies": {
- "@kibalabs/core": "^0.7.2-next.9",
- "@kibalabs/core-react": "^0.10.1-next.7",
+ "@kibalabs/core": "^0.7.2-next.10",
"lazysizes": "^5.3.2",
"markdown-to-jsx": "^9.10.3"
},
"devDependencies": {
- "@kibalabs/build": "0.14.2-next.14",
+ "@kibalabs/build": "0.14.2-next.16",
"@storybook/addon-docs": "10.6.4",
"@storybook/react-vite": "10.6.4",
"@types/react": "19.3.0",
"@types/react-dom": "19.3.0",
"react": "19.3.1",
"react-dom": "19.3.1",
+ "react-dropzone": "20.1.4",
+ "react-hot-toast": "2.6.1",
+ "react-router": "8.5.0",
"remark-gfm": "4.0.1",
"storybook": "10.6.4"
},
"peerDependencies": {
"react": "^19.0.0",
- "react-dom": "^19.0.0"
+ "react-dom": "^19.0.0",
+ "react-dropzone": "^20.1.4",
+ "react-hot-toast": "^2.6.1",
+ "react-router": "^8.5.0"
+ },
+ "peerDependenciesMeta": {
+ "react-dropzone": {
+ "optional": true
+ },
+ "react-hot-toast": {
+ "optional": true
+ }
}
}
diff --git a/src/app/kibaApp.tsx b/src/app/kibaApp.tsx
index bb98eac8..9999c13d 100644
--- a/src/app/kibaApp.tsx
+++ b/src/app/kibaApp.tsx
@@ -1,7 +1,7 @@
import React from 'react';
import { getClassName } from '@kibalabs/core';
-import { getIsRunningOnBrowser, IMultiAnyChildProps, useInitialization } from '@kibalabs/core-react';
+import { getIsRunningOnBrowser, IMultiAnyChildProps, useInitialization } from '@kibalabs/core/react';
import { GlobalCss } from './globalCss';
import { BackgroundView, IBackgroundConfig } from '../wrappers';
diff --git a/src/atoms/bulletList/component.tsx b/src/atoms/bulletList/component.tsx
index e0d96b0d..ecd32b15 100644
--- a/src/atoms/bulletList/component.tsx
+++ b/src/atoms/bulletList/component.tsx
@@ -1,7 +1,7 @@
import React from 'react';
import { getClassName } from '@kibalabs/core';
-import { IMultiChildProps } from '@kibalabs/core-react';
+import { IMultiChildProps } from '@kibalabs/core/react';
import './styles.scss';
import { IComponentProps } from '../../model';
diff --git a/src/atoms/bulletText/component.tsx b/src/atoms/bulletText/component.tsx
index f78f40e8..df0ea481 100644
--- a/src/atoms/bulletText/component.tsx
+++ b/src/atoms/bulletText/component.tsx
@@ -1,7 +1,7 @@
import React from 'react';
import { getClassName } from '@kibalabs/core';
-import { IOptionalSingleChildProps } from '@kibalabs/core-react';
+import { IOptionalSingleChildProps } from '@kibalabs/core/react';
import './styles.scss';
import { IComponentProps } from '../../model';
diff --git a/src/atoms/button/component.tsx b/src/atoms/button/component.tsx
index ad225621..d0e17a86 100644
--- a/src/atoms/button/component.tsx
+++ b/src/atoms/button/component.tsx
@@ -1,7 +1,7 @@
import React from 'react';
import { getClassName } from '@kibalabs/core';
-import { Link as CoreLink, OptionalProppedElement, useIsCoreRoutingEnabled } from '@kibalabs/core-react';
+import { Link as CoreLink, OptionalProppedElement, useIsCoreRoutingEnabled } from '@kibalabs/core/react';
import './styles.scss';
import { Alignment, IComponentProps } from '../../model';
diff --git a/src/atoms/collapsibleBox/component.tsx b/src/atoms/collapsibleBox/component.tsx
index 2335a818..65011b2d 100644
--- a/src/atoms/collapsibleBox/component.tsx
+++ b/src/atoms/collapsibleBox/component.tsx
@@ -1,7 +1,7 @@
import React from 'react';
import { getClassName } from '@kibalabs/core';
-import { ISingleAnyChildProps } from '@kibalabs/core-react';
+import { ISingleAnyChildProps } from '@kibalabs/core/react';
import './styles.scss';
import { IComponentProps } from '../../model';
diff --git a/src/atoms/collapsibleBox/componentStateful.tsx b/src/atoms/collapsibleBox/componentStateful.tsx
index f8127aa6..0dc16010 100644
--- a/src/atoms/collapsibleBox/componentStateful.tsx
+++ b/src/atoms/collapsibleBox/componentStateful.tsx
@@ -1,7 +1,7 @@
import React from 'react';
import { getClassName } from '@kibalabs/core';
-import { ISingleAnyChildProps } from '@kibalabs/core-react';
+import { ISingleAnyChildProps } from '@kibalabs/core/react';
import { CollapsibleBox } from './component';
import { IComponentProps } from '../../model';
diff --git a/src/atoms/dialog/component.tsx b/src/atoms/dialog/component.tsx
index 4f6a9b93..efd9857e 100644
--- a/src/atoms/dialog/component.tsx
+++ b/src/atoms/dialog/component.tsx
@@ -1,7 +1,7 @@
import React from 'react';
import { getClassName } from '@kibalabs/core';
-import { getIsRunningOnBrowser, ISingleAnyChildProps, useEventListener } from '@kibalabs/core-react';
+import { getIsRunningOnBrowser, ISingleAnyChildProps, useEventListener } from '@kibalabs/core/react';
import { IComponentProps } from '../../model';
import { Box } from '../../particles/box';
diff --git a/src/atoms/iconButton/component.tsx b/src/atoms/iconButton/component.tsx
index 7f060993..37039aa4 100644
--- a/src/atoms/iconButton/component.tsx
+++ b/src/atoms/iconButton/component.tsx
@@ -1,7 +1,7 @@
import React from 'react';
import { getClassName } from '@kibalabs/core';
-import { Link as CoreLink, useIsCoreRoutingEnabled } from '@kibalabs/core-react';
+import { Link as CoreLink, useIsCoreRoutingEnabled } from '@kibalabs/core/react';
import './styles.scss';
import { IComponentProps } from '../../model';
diff --git a/src/atoms/inputWrapper/component.tsx b/src/atoms/inputWrapper/component.tsx
index ff73f684..1ec10332 100644
--- a/src/atoms/inputWrapper/component.tsx
+++ b/src/atoms/inputWrapper/component.tsx
@@ -1,7 +1,7 @@
import React from 'react';
import { getClassName } from '@kibalabs/core';
-import { ISingleAnyChildProps } from '@kibalabs/core-react';
+import { ISingleAnyChildProps } from '@kibalabs/core/react';
import './styles.scss';
import { IComponentProps } from '../../model';
diff --git a/src/atoms/link/component.tsx b/src/atoms/link/component.tsx
index 3e40cf57..2b41c399 100644
--- a/src/atoms/link/component.tsx
+++ b/src/atoms/link/component.tsx
@@ -1,7 +1,7 @@
import React from 'react';
import { getClassName } from '@kibalabs/core';
-import { Link as CoreLink, useIsCoreRoutingEnabled } from '@kibalabs/core-react';
+import { Link as CoreLink, useIsCoreRoutingEnabled } from '@kibalabs/core/react';
import './styles.scss';
import { IComponentProps } from '../../model';
diff --git a/src/atoms/linkBase/component.tsx b/src/atoms/linkBase/component.tsx
index c2729e6e..76779525 100644
--- a/src/atoms/linkBase/component.tsx
+++ b/src/atoms/linkBase/component.tsx
@@ -1,7 +1,7 @@
import React from 'react';
import { getClassName } from '@kibalabs/core';
-import { Link as CoreLink, ISingleAnyChildProps, useIsCoreRoutingEnabled } from '@kibalabs/core-react';
+import { Link as CoreLink, ISingleAnyChildProps, useIsCoreRoutingEnabled } from '@kibalabs/core/react';
import './styles.scss';
import { IComponentProps } from '../../model';
diff --git a/src/atoms/listItem/component.tsx b/src/atoms/listItem/component.tsx
index aa406cd6..d268d3c8 100644
--- a/src/atoms/listItem/component.tsx
+++ b/src/atoms/listItem/component.tsx
@@ -1,7 +1,7 @@
import React from 'react';
import { getClassName } from '@kibalabs/core';
-import { ISingleAnyChildProps } from '@kibalabs/core-react';
+import { ISingleAnyChildProps } from '@kibalabs/core/react';
import './styles.scss';
import { IComponentProps } from '../../model';
diff --git a/src/atoms/prettyText/component.tsx b/src/atoms/prettyText/component.tsx
index 17a0a9cb..0b81e1c7 100644
--- a/src/atoms/prettyText/component.tsx
+++ b/src/atoms/prettyText/component.tsx
@@ -1,7 +1,7 @@
import React from 'react';
import { getClassName } from '@kibalabs/core';
-import { IMultiAnyChildProps } from '@kibalabs/core-react';
+import { IMultiAnyChildProps } from '@kibalabs/core/react';
import './styles.scss';
import { IComponentProps } from '../../model';
diff --git a/src/atoms/selectableView/component.tsx b/src/atoms/selectableView/component.tsx
index 185d610c..b4a1c264 100644
--- a/src/atoms/selectableView/component.tsx
+++ b/src/atoms/selectableView/component.tsx
@@ -1,7 +1,7 @@
import React from 'react';
import { getClassName } from '@kibalabs/core';
-import { ISingleAnyChildProps } from '@kibalabs/core-react';
+import { ISingleAnyChildProps } from '@kibalabs/core/react';
import './styles.scss';
import { Stack } from '../../layouts';
diff --git a/src/atoms/titledCollapsibleBox/component.tsx b/src/atoms/titledCollapsibleBox/component.tsx
index fc801ce4..cd998cd5 100644
--- a/src/atoms/titledCollapsibleBox/component.tsx
+++ b/src/atoms/titledCollapsibleBox/component.tsx
@@ -1,7 +1,7 @@
import React from 'react';
import { getClassName } from '@kibalabs/core';
-import { ISingleAnyChildProps } from '@kibalabs/core-react';
+import { ISingleAnyChildProps } from '@kibalabs/core/react';
import './styles.scss';
import { IComponentProps } from '../../model';
diff --git a/src/atoms/titledCollapsibleBox/componentStateful.tsx b/src/atoms/titledCollapsibleBox/componentStateful.tsx
index b0601f7c..2e7b6f6e 100644
--- a/src/atoms/titledCollapsibleBox/componentStateful.tsx
+++ b/src/atoms/titledCollapsibleBox/componentStateful.tsx
@@ -1,7 +1,7 @@
import React from 'react';
import { getClassName } from '@kibalabs/core';
-import { ISingleAnyChildProps } from '@kibalabs/core-react';
+import { ISingleAnyChildProps } from '@kibalabs/core/react';
import { TitledCollapsibleBox } from './component';
import { IComponentProps } from '../../model';
diff --git a/src/atoms/webView/component.tsx b/src/atoms/webView/component.tsx
index 60637780..7b409334 100644
--- a/src/atoms/webView/component.tsx
+++ b/src/atoms/webView/component.tsx
@@ -1,7 +1,7 @@
import React from 'react';
import { getClassName } from '@kibalabs/core';
-import { useInitialization } from '@kibalabs/core-react';
+import { useInitialization } from '@kibalabs/core/react';
import './styles.scss';
import { IComponentProps } from '../../model';
diff --git a/src/dropzone/component.tsx b/src/dropzone/component.tsx
new file mode 100644
index 00000000..896669f1
--- /dev/null
+++ b/src/dropzone/component.tsx
@@ -0,0 +1,68 @@
+import React from 'react';
+
+import { getClassName } from '@kibalabs/core';
+import { IMultiAnyChildProps } from '@kibalabs/core/react';
+import * as ReactDropzone from 'react-dropzone';
+
+import { KibaIcon } from '..';
+
+export interface IDropzoneProps extends IMultiAnyChildProps {
+ id?: string;
+ className?: string;
+ style?: React.CSSProperties;
+ onFilesChosen: (files: File[]) => void;
+ fileMimeTypes?: string[];
+ fileMimeTypeExtensions?: Record;
+ fileLimit?: number;
+ isDisabled?: boolean;
+}
+
+export function Dropzone(props: IDropzoneProps): React.ReactElement {
+ const { onFilesChosen, fileLimit, isDisabled, fileMimeTypeExtensions, fileMimeTypes, id, className, style, children } = props;
+ const onDrop = React.useCallback((files: File[]) => {
+ onFilesChosen(files);
+ }, [onFilesChosen]);
+ const { getRootProps, getInputProps, isDragActive } = ReactDropzone.useDropzone({
+ onDrop,
+ maxFiles: fileLimit,
+ disabled: isDisabled,
+ accept: fileMimeTypeExtensions ?? ((fileMimeTypes || []).reduce((accumulator: Record, current: string): Record => {
+ accumulator[current] = [];
+ return accumulator;
+ }, {})),
+ });
+ const rootProps = getRootProps();
+ const inputProps = getInputProps();
+ return (
+