@liguelead/design-system 0.0.35 → 0.0.36

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.
@@ -55,6 +55,11 @@ Componente de alerta para comunicar mensagens de feedback ao usuário.
55
55
  control: 'text',
56
56
  description: 'URL do botão de ação',
57
57
  },
58
+ openNewTab: {
59
+ control: 'boolean',
60
+ description: 'Abre o link do botão em uma nova aba',
61
+ table: { defaultValue: { summary: 'false' } },
62
+ },
58
63
  },
59
64
  }
60
65
 
@@ -87,13 +92,14 @@ export const TodasVariantes: Story = {
87
92
  export const ComBotao: Story = {
88
93
  name: 'Com botão de ação',
89
94
  parameters: {
90
- docs: { description: { story: 'Use `hasButton` quando houver uma ação clara para o usuário tomar.' } },
95
+ docs: { description: { story: 'Use `hasButton` quando houver uma ação clara para o usuário tomar. Use `openNewTab` para abrir o link em nova aba.' } },
91
96
  },
92
97
  render: () => (
93
98
  <div style={{ display: 'flex', flexDirection: 'column', gap: 12 }}>
94
- <Alert variant="info" title="Nova versão disponível" description="Uma atualização está pronta para ser instalada." hasButton buttonLabel="Atualizar agora" href="#" />
95
- <Alert variant="warning" title="Sessão expirando" description="Sua sessão expira em 5 minutos." hasButton buttonLabel="Renovar sessão" href="#" />
96
- <Alert variant="danger" title="Falha no pagamento" description="Não foi possível processar seu pagamento." hasButton buttonLabel="Tentar novamente" href="#" />
99
+ <Alert variant="info" title="Nova versão disponível" description="Uma atualização está pronta para ser instalada." hasButton buttonLabel="Atualizar agora" href="#" openNewTab={false} />
100
+ <Alert variant="warning" title="Sessão expirando" description="Sua sessão expira em 5 minutos." hasButton buttonLabel="Renovar sessão" href="#" openNewTab={false} />
101
+ <Alert variant="danger" title="Falha no pagamento" description="Não foi possível processar seu pagamento." hasButton buttonLabel="Tentar novamente" href="#" openNewTab={false} />
102
+ <Alert variant="info" title="Documentação disponível" description="Acesse a documentação completa no portal." hasButton buttonLabel="Ver documentação" href="#" openNewTab />
97
103
  </div>
98
104
  ),
99
105
  }
@@ -17,6 +17,7 @@ const Alert = ({
17
17
  description,
18
18
  href,
19
19
  children,
20
+ openNewTab,
20
21
  title,
21
22
  hasButton
22
23
  }: TAlertProps) => {
@@ -45,7 +46,12 @@ const Alert = ({
45
46
  </AlertContent>
46
47
  {hasButton && (
47
48
  <AlertButtonContainer>
48
- <LinkButton href={href || ''}>{buttonLabel}</LinkButton>
49
+ <LinkButton
50
+ href={href || ''}
51
+ target={openNewTab ? '_blank' : undefined}
52
+ >
53
+ {buttonLabel}
54
+ </LinkButton>
49
55
  </AlertButtonContainer>
50
56
  )}
51
57
  </AlertContainer>
@@ -7,4 +7,5 @@ export type TAlertProps = {
7
7
  description?: string
8
8
  variant?: 'default' | 'danger' | 'warning' | 'info' | 'success'
9
9
  title: string
10
+ openNewTab?: boolean
10
11
  }
@@ -0,0 +1,126 @@
1
+ import type { Meta, StoryObj } from '@storybook/react-vite'
2
+ import Skeleton from './Skeleton'
3
+
4
+ const meta: Meta<typeof Skeleton> = {
5
+ title: 'Feedback/Skeleton',
6
+ component: Skeleton,
7
+ parameters: {
8
+ layout: 'centered',
9
+ docs: {
10
+ description: {
11
+ component: `
12
+ Componente de loading skeleton baseado em \`react-loading-skeleton\`.
13
+
14
+ **Quando usar:**
15
+ - Enquanto dados estão sendo carregados da API
16
+ - Para evitar layout shift e melhorar a percepção de performance
17
+ - Substitua o conteúdo real pelo Skeleton durante o estado de loading
18
+ `,
19
+ },
20
+ },
21
+ },
22
+ tags: ['autodocs'],
23
+ argTypes: {
24
+ width: {
25
+ control: 'text',
26
+ description: 'Largura do skeleton (px, %, rem...)',
27
+ },
28
+ height: {
29
+ control: 'text',
30
+ description: 'Altura do skeleton',
31
+ },
32
+ count: {
33
+ control: { type: 'number', min: 1, max: 10 },
34
+ description: 'Quantidade de linhas',
35
+ table: { defaultValue: { summary: '1' } },
36
+ },
37
+ circle: {
38
+ control: 'boolean',
39
+ description: 'Formato circular (avatar)',
40
+ table: { defaultValue: { summary: 'false' } },
41
+ },
42
+ borderRadius: {
43
+ control: 'text',
44
+ description: 'Border radius customizado',
45
+ },
46
+ inline: {
47
+ control: 'boolean',
48
+ description: 'Exibe inline',
49
+ table: { defaultValue: { summary: 'false' } },
50
+ },
51
+ },
52
+ }
53
+
54
+ export default meta
55
+ type Story = StoryObj<typeof meta>
56
+
57
+ export const Default: Story = {
58
+ args: {
59
+ width: 200,
60
+ height: 20,
61
+ },
62
+ }
63
+
64
+ export const MultiplaLinhas: Story = {
65
+ name: 'Múltiplas linhas',
66
+ parameters: {
67
+ docs: { description: { story: 'Use `count` para simular blocos de texto.' } },
68
+ },
69
+ render: () => (
70
+ <div style={{ width: 320 }}>
71
+ <Skeleton count={4} height={16} />
72
+ </div>
73
+ ),
74
+ }
75
+
76
+ export const Circular: Story = {
77
+ name: 'Avatar circular',
78
+ parameters: {
79
+ docs: { description: { story: 'Use `circle` para avatares.' } },
80
+ },
81
+ render: () => (
82
+ <div style={{ display: 'flex', gap: 12, alignItems: 'center' }}>
83
+ <Skeleton circle width={32} height={32} />
84
+ <Skeleton circle width={40} height={40} />
85
+ <Skeleton circle width={56} height={56} />
86
+ </div>
87
+ ),
88
+ }
89
+
90
+ export const Card: Story = {
91
+ name: 'Card de conteúdo',
92
+ parameters: {
93
+ docs: { description: { story: 'Exemplo de skeleton para um card com avatar + texto.' } },
94
+ },
95
+ render: () => (
96
+ <div style={{ display: 'flex', flexDirection: 'column', gap: 12, width: 320 }}>
97
+ <div style={{ display: 'flex', gap: 12, alignItems: 'center' }}>
98
+ <Skeleton circle width={40} height={40} />
99
+ <div style={{ flex: 1 }}>
100
+ <Skeleton height={14} width="60%" />
101
+ <Skeleton height={12} width="40%" />
102
+ </div>
103
+ </div>
104
+ <Skeleton height={120} borderRadius={8} />
105
+ <Skeleton count={3} height={14} />
106
+ </div>
107
+ ),
108
+ }
109
+
110
+ export const Tabela: Story = {
111
+ name: 'Linhas de tabela',
112
+ parameters: {
113
+ docs: { description: { story: 'Simula linhas de uma tabela carregando.' } },
114
+ },
115
+ render: () => (
116
+ <div style={{ display: 'flex', flexDirection: 'column', gap: 8, width: 480 }}>
117
+ {Array.from({ length: 5 }).map((_, i) => (
118
+ <div key={i} style={{ display: 'flex', gap: 16 }}>
119
+ <Skeleton width={120} height={16} />
120
+ <Skeleton width={160} height={16} />
121
+ <Skeleton width={80} height={16} />
122
+ </div>
123
+ ))}
124
+ </div>
125
+ ),
126
+ }
@@ -0,0 +1,15 @@
1
+ import styled from 'styled-components'
2
+ import { radius } from '@liguelead/foundation'
3
+ import { parseColor } from '../../utils'
4
+
5
+ export const SkeletonWrapper = styled.div<{ $inline?: boolean }>`
6
+ display: ${({ $inline }) => ($inline ? 'inline-flex' : 'flex')};
7
+ flex-direction: column;
8
+ gap: 4px;
9
+ `
10
+
11
+ export const SkeletonThemeWrapper = styled.div`
12
+ --base-color: ${({ theme }) => parseColor(theme.colors.neutral200)};
13
+ --highlight-color: ${({ theme }) => parseColor(theme.colors.neutral100)};
14
+ border-radius: ${radius.radius4}px;
15
+ `
@@ -0,0 +1,38 @@
1
+ import ReactSkeleton, { SkeletonTheme } from 'react-loading-skeleton'
2
+ import 'react-loading-skeleton/dist/skeleton.css'
3
+ import { useTheme } from 'styled-components'
4
+ import { parseColor } from '../../utils'
5
+ import { SkeletonWrapper } from './Skeleton.styles'
6
+ import { SkeletonProps } from './Skeleton.types'
7
+
8
+ const Skeleton: React.FC<SkeletonProps> = ({
9
+ width,
10
+ height,
11
+ borderRadius,
12
+ circle = false,
13
+ count = 1,
14
+ className,
15
+ inline = false,
16
+ }) => {
17
+ const theme = useTheme()
18
+
19
+ return (
20
+ <SkeletonTheme
21
+ baseColor={parseColor(theme.colors.neutral200)}
22
+ highlightColor={parseColor(theme.colors.neutral100)}
23
+ >
24
+ <SkeletonWrapper $inline={inline} className={className}>
25
+ <ReactSkeleton
26
+ width={width}
27
+ height={height}
28
+ borderRadius={borderRadius}
29
+ circle={circle}
30
+ count={count}
31
+ inline={inline}
32
+ />
33
+ </SkeletonWrapper>
34
+ </SkeletonTheme>
35
+ )
36
+ }
37
+
38
+ export default Skeleton
@@ -0,0 +1,9 @@
1
+ export interface SkeletonProps {
2
+ width?: string | number
3
+ height?: string | number
4
+ borderRadius?: string | number
5
+ circle?: boolean
6
+ count?: number
7
+ className?: string
8
+ inline?: boolean
9
+ }
@@ -0,0 +1,2 @@
1
+ export { default as Skeleton } from './Skeleton'
2
+ export type { SkeletonProps } from './Skeleton.types'
@@ -21,3 +21,5 @@ export { Combobox } from './Combobox'
21
21
  export { default as SplitButton } from './SplitButton'
22
22
  export { default as Table } from './Table'
23
23
  export { default as Tabs } from './Tabs'
24
+ export { Skeleton } from './Skeleton'
25
+ export type { SkeletonProps } from './Skeleton'
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "@liguelead/design-system",
3
- "version": "0.0.35",
3
+ "version": "0.0.36",
4
4
  "type": "module",
5
5
  "main": "components/index.ts",
6
6
  "publishConfig": {
@@ -25,7 +25,8 @@
25
25
  "react-toastify": "^11.0.5",
26
26
  "cmdk": "^1.1.1",
27
27
  "date-fns": "^2.30.0",
28
- "@tanstack/react-table": "^8.0.0"
28
+ "@tanstack/react-table": "^8.0.0",
29
+ "react-loading-skeleton": "^3.5.0"
29
30
  },
30
31
  "scripts": {
31
32
  "lint": "eslint ."