diff --git a/package.json b/package.json
index 40e879b..537a1a1 100644
--- a/package.json
+++ b/package.json
@@ -21,7 +21,7 @@
},
"devDependencies": {
"@chromatic-com/storybook": "1",
- "@floating-ui/react": "^0.26.15",
+ "@floating-ui/react": "^0.26.16",
"@ianvs/prettier-plugin-sort-imports": "^4.2.1",
"@material/material-color-utilities": "^0.2.7",
"@mdi/js": "^7.4.47",
@@ -34,10 +34,10 @@
"@storybook/react-vite": "^8.1.1",
"@types/react": "^18.3.2",
"@types/react-dom": "^18.3.0",
- "@typescript-eslint/eslint-plugin": "^7.9.0",
- "@typescript-eslint/parser": "^7.9.0",
+ "@typescript-eslint/eslint-plugin": "^7.10.0",
+ "@typescript-eslint/parser": "^7.10.0",
"@vitejs/plugin-react": "^4.2.1",
- "chromatic": "^11.3.2",
+ "chromatic": "^11.3.5",
"clsx": "^2.1.1",
"eslint": "^8.57.0",
"eslint-plugin-react-hooks": "^4.6.2",
@@ -45,7 +45,7 @@
"eslint-plugin-storybook": "^0.8.0",
"glob": "^10.3.15",
"prettier": "^3.2.5",
- "sass": "^1.77.1",
+ "sass": "^1.77.2",
"storybook": "^8.1.1",
"styled-jsx": "^5.1.3",
"typescript": "^5.4.5",
diff --git a/src/components/tabs/Tabs.stories.tsx b/src/components/tabs/Tabs.stories.tsx
index ec35855..ca1c071 100644
--- a/src/components/tabs/Tabs.stories.tsx
+++ b/src/components/tabs/Tabs.stories.tsx
@@ -94,10 +94,38 @@ export const Scrolling: Story = {
],
args: {
items: [
- 1, 666666, 8080, 3, 443, 8888, 1, 666666, 8080, 3, 443, 8888,
+ 20, 21, 22, 23, 25, 53, 67, 68, 69, 80, 110, 119, 123, 137, 138,
+ 139, 143, 161, 162, 179, 194, 443, 465, 514, 515, 587, 636, 993,
+ 995, 1080, 1194, 1433, 1434, 1521, 1723, 1812, 1813, 2049, 3306,
+ 3389, 5060, 5061, 5432, 5900, 6379, 8080, 8443, 27017, 27018, 27019,
+ 27020, 50000,
].map((i, value) => ({
label: `Tab ${i}`,
value: String(value),
})),
},
}
+
+export const Block: Story = {
+ args: {
+ variant: 'block',
+ defaultValue: 'Tab 1',
+ items: [
+ {
+ value: 'Tab 1',
+ icon: ,
+ direction: 'row',
+ },
+ {
+ value: 'Tab 2',
+ icon: ,
+ direction: 'row',
+ },
+ {
+ value: 'Tab 3',
+ icon: ,
+ direction: 'row',
+ },
+ ],
+ },
+}
diff --git a/src/components/tabs/Tabs.tsx b/src/components/tabs/Tabs.tsx
index 883c327..61de75f 100644
--- a/src/components/tabs/Tabs.tsx
+++ b/src/components/tabs/Tabs.tsx
@@ -36,7 +36,7 @@ export const Tabs = forwardRef<
/**
* @default "primary"
*/
- variant?: 'primary' | 'secondary'
+ variant?: 'primary' | 'secondary' | 'block'
full?: boolean
}>
>(function Tab(
@@ -68,7 +68,10 @@ export const Tabs = forwardRef<
if (!item) return
- const indicatorWidth = variant === 'secondary' ? item.clientWidth : 36
+ const indicatorWidth =
+ variant === 'secondary' || variant === 'block'
+ ? item.clientWidth
+ : 36
setWidth(`${indicatorWidth}px`)
const left = item.offsetLeft + (item.clientWidth - indicatorWidth) / 2
setLeft(`${left}px`)
@@ -131,6 +134,9 @@ export const Tabs = forwardRef<
setValue(item.value)}
diff --git a/src/components/tabs/tabs.scss b/src/components/tabs/tabs.scss
index 48315ff..b351599 100644
--- a/src/components/tabs/tabs.scss
+++ b/src/components/tabs/tabs.scss
@@ -20,8 +20,8 @@
user-select: none;
cursor: pointer;
overflow: hidden;
-
- padding: 0.5rem 1rem 0.8rem 1rem;
+ padding: 0.5rem 1rem;
+ padding-bottom: 0.8rem; // for indicator
display: inline-flex;
align-items: center;
flex-direction: column;
@@ -86,6 +86,11 @@
bottom: -3px;
// left: calc in js
}
+ &[data-sd-variant='primary'] {
+ .sd-tabs-active_indicator {
+ clip-path: inset(0 0 50% 0);
+ }
+ }
&[data-sd-variant='secondary'] {
.sd-tabs-active_indicator {
// width: calc in js
@@ -94,4 +99,21 @@
bottom: 0;
}
}
+ &[data-sd-variant='block'] {
+ border-radius: 8px;
+ overflow: hidden;
+ background-color: var(--md-sys-color-surface-container-highest);
+ .sd-tabs-item {
+ background-color: transparent;
+ z-index: 1;
+ padding-bottom: 0.5rem; // reset
+ }
+ .sd-tabs-active_indicator {
+ inset: 0;
+ height: 100%;
+ width: 100%;
+ background-color: var(--md-sys-color-background);
+ clip-path: inset(2px round 4px);
+ }
+ }
}
diff --git a/src/composition/Skeleton/Skeleton.scss b/src/composition/Skeleton/Skeleton.scss
new file mode 100644
index 0000000..eba2f73
--- /dev/null
+++ b/src/composition/Skeleton/Skeleton.scss
@@ -0,0 +1,14 @@
+.sd-skeleton {
+ background: linear-gradient(90deg, #f0f0f0 25%, #e0e0e0 50%, #f0f0f0 75%);
+ background-size: 200% 100%;
+ animation: sd-skeleton-shimmer 1.5s infinite ease-out;
+}
+
+@keyframes sd-skeleton-shimmer {
+ 0% {
+ background-position: 100% 0;
+ }
+ 100% {
+ background-position: -100% 0;
+ }
+}
diff --git a/src/composition/Skeleton/Skeleton.stories.tsx b/src/composition/Skeleton/Skeleton.stories.tsx
new file mode 100644
index 0000000..c83e048
--- /dev/null
+++ b/src/composition/Skeleton/Skeleton.stories.tsx
@@ -0,0 +1,19 @@
+import type { Meta, StoryObj } from '@storybook/react'
+import { Skeleton } from './Skeleton'
+
+const meta: Meta = {
+ title: 'composition/Skeleton',
+ component: Skeleton,
+ tags: ['autodocs'],
+}
+
+export default meta
+
+type Story = StoryObj
+
+export const Default: Story = {
+ args: {
+ height: '2rem',
+ borderRadius: '4px',
+ },
+}
diff --git a/src/composition/Skeleton/Skeleton.tsx b/src/composition/Skeleton/Skeleton.tsx
new file mode 100644
index 0000000..cc22427
--- /dev/null
+++ b/src/composition/Skeleton/Skeleton.tsx
@@ -0,0 +1,9 @@
+import { forwardRef } from 'react'
+import './Skeleton.scss'
+
+export const Skeleton = forwardRef<
+ HTMLDivElement,
+ Partial
+>(({ ...style }) => {
+ return
+})
diff --git a/src/composition/Skeleton/index.ts b/src/composition/Skeleton/index.ts
new file mode 100644
index 0000000..4220e69
--- /dev/null
+++ b/src/composition/Skeleton/index.ts
@@ -0,0 +1 @@
+export * from './Skeleton'
diff --git a/src/documentation/ColorSchemes.mdx b/src/documentation/ColorSchemes.mdx
index d034cef..c0ce3d0 100644
--- a/src/documentation/ColorSchemes.mdx
+++ b/src/documentation/ColorSchemes.mdx
@@ -1,7 +1,6 @@
import { ChangeTheme } from './components/ChangeTheme'
import { ColorStatic } from './components/ColorSchemes'
-
@@ -9,4 +8,4 @@ import { ColorStatic } from './components/ColorSchemes'
Refer to [https://m3.material.io/styles/color/static/baseline](https://m3.material.io/styles/color/static/baseline)
-
\ No newline at end of file
+
diff --git a/src/documentation/Fonts.mdx b/src/documentation/Fonts.mdx
index fdb6e17..e0b8edc 100644
--- a/src/documentation/Fonts.mdx
+++ b/src/documentation/Fonts.mdx
@@ -26,4 +26,4 @@ Chinese user may prefer:
* {
font-family: 'Google Sans', sans-serif;
}
-```
\ No newline at end of file
+```
diff --git a/src/documentation/Icons.mdx b/src/documentation/Icons.mdx
index bcf44b5..01e57be 100644
--- a/src/documentation/Icons.mdx
+++ b/src/documentation/Icons.mdx
@@ -1,7 +1,7 @@
# Icons
This library uses the [MDI Icon Library](https://pictogrammers.com/library/mdi/).
-You can refer to it at [Material Design Icons](https://materialdesignicons.com/).
+You can refer to it at [Material Design Icons](https://materialdesignicons.com/).
```tsx
import { mdiMagnify } from '@mdi/js'
@@ -16,4 +16,4 @@ const App = () => (
)
```
-A replacement is icons from [Google fonts](https://fonts.google.com/icons).
\ No newline at end of file
+A replacement is icons from [Google fonts](https://fonts.google.com/icons).
diff --git a/src/documentation/Theming.mdx b/src/documentation/Theming.mdx
index 96c574a..4496044 100644
--- a/src/documentation/Theming.mdx
+++ b/src/documentation/Theming.mdx
@@ -1,6 +1,6 @@
# Theming
-This library uses the official material design css variables (`--md-sys-color-`, at `:root`) to theming.
+This library uses the official material design css variables (`--md-sys-color-`, at `:root`) to theming.
```ts
// create theme
@@ -19,7 +19,11 @@ It's actually a module that provides some helper function and re-export the [@ma
Here is a demo showing these wrapper functions, which can make theming easier.
```tsx
-import { applyThemeForSoda, themeFromHexString, themeFromImageOrFile } from 'soda/dist/utils/theme'
+import {
+ applyThemeForSoda,
+ themeFromHexString,
+ themeFromImageOrFile,
+} from 'soda/dist/utils/theme'
// simply
applyThemeForSoda('#f82506')
@@ -53,4 +57,4 @@ function SelectThemeFromFileButton() {
}
return
}
-```
\ No newline at end of file
+```
diff --git a/src/documentation/ZIndex.mdx b/src/documentation/ZIndex.mdx
index eab62c7..2a5f7f7 100644
--- a/src/documentation/ZIndex.mdx
+++ b/src/documentation/ZIndex.mdx
@@ -1,9 +1,9 @@
-import { Table } from "../composition/Table"
+import { Table } from '../composition/Table'
# zIndex
Some components feature a `fixed` boolean property, which, when set to `true`, changes the component's position to `position: fixed`.
-Additionally, while components come with a default `zIndex` value, this can be overridden by setting the `zIndex` property.
+Additionally, while components come with a default `zIndex` value, this can be overridden by setting the `zIndex` property.
The components also expose an `inset` property, allowing for precise control over their positioning.
```tsx
@@ -16,13 +16,27 @@ Currently, the default `zIndex` is:
- Component | zIndex |
+
+ Component |
+ zIndex |
+
- snackbar | 1 |
- app-bar | 1 |
- navigation | 2 |
- sheet | 3 |
+
+ snackbar |
+ 1 |
+
+
+ app-bar |
+ 1 |
+
+
+ navigation |
+ 2 |
+
+
+ sheet |
+ 3 |
+
-
\ No newline at end of file
diff --git a/src/documentation/components/Demo.tsx b/src/documentation/components/Demo.tsx
index 1361cd2..97af3c1 100644
--- a/src/documentation/components/Demo.tsx
+++ b/src/documentation/components/Demo.tsx
@@ -65,7 +65,6 @@ function LayoutNavigationDrawer({ children }: { children?: React.ReactNode }) {
if (!div.className.includes('sd-')) return
div.classList.add('sb-unstyled')
})
-
}, [isScreenExpanded])
const containerRef = useRef(null)
const [fullscreen, setFullscreen] = useFullscreen(containerRef)