Skip to content

Commit e6cda35

Browse files
authored
fix: button dynamic classes (#106)
* chore: added the shared folder * feat(component): now the Daisy Button component supports all the Daisy properties The button now supports all Daisy modifiers (primary, secondary), sizes (xs, sm, ...) and other properties. A new clsq utility (a TS clone of the famous clsx utility) has been added a new shared folder (I have also created an alias in order to be easily imported everywhere)
1 parent 70d9483 commit e6cda35

File tree

8 files changed

+247
-16
lines changed

8 files changed

+247
-16
lines changed

packages/daisy/src/components/button/button.tsx

Lines changed: 69 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -1,13 +1,80 @@
11
import { component$, QwikIntrinsicElements, Slot } from '@builder.io/qwik';
22
import { Button as HeadlessButton } from '@qwik-ui/headless';
3+
import { clsq } from '@qwik-ui/shared';
34

4-
export type ButtonProps = QwikIntrinsicElements['button'];
5+
export type HTMLButtonProps = QwikIntrinsicElements['button'];
56

7+
export type DaisyButtonProps = {
8+
noAnimation?: boolean;
9+
glass?: boolean;
10+
loading?: boolean;
11+
circle?: boolean;
12+
square?: boolean;
13+
active?: boolean;
14+
disabled?: boolean;
15+
outline?: boolean;
16+
size?: 'xs' | 'sm' | 'md' | 'lg' | 'block' | 'wide';
17+
} & DaisyButtonModifiers;
18+
19+
export type DaisyButtonModifiers = {
20+
primary?: boolean;
21+
secondary?: boolean;
22+
accent?: boolean;
23+
info?: boolean;
24+
success?: boolean;
25+
warning?: boolean;
26+
error?: boolean;
27+
ghost?: boolean;
28+
link?: boolean;
29+
}
30+
31+
export type ButtonProps = HTMLButtonProps & DaisyButtonProps ;
632

733
export const Button = component$(
834
(props: ButtonProps) => {
35+
const {
36+
class: cls,
37+
primary, secondary, accent, info, success, warning, error, ghost, link, outline, active, disabled, glass, loading, noAnimation,
38+
circle,
39+
square,
40+
size = 'md',
41+
...rest } = props;
42+
943
return (
10-
<HeadlessButton class="btn btn-primary" {...props}>
44+
<HeadlessButton
45+
{...rest}
46+
class={
47+
clsq(
48+
'btn',
49+
{
50+
// modifiers
51+
'btn-primary': primary,
52+
'btn-secondary': secondary,
53+
'btn-accent': accent,
54+
'btn-info': info,
55+
'btn-success': success,
56+
'btn-warning': warning,
57+
'btn-error': error,
58+
'btn-ghost': ghost,
59+
'btn-link': link,
60+
'btn-active': active,
61+
// daisy props
62+
'btn-outline': outline,
63+
'btn-disabled': disabled,
64+
'glass': glass,
65+
'loading': loading,
66+
'no-animation': noAnimation,
67+
'btn-circle': circle,
68+
'btn-square': square,
69+
// size
70+
'btn-xs': size === 'xs',
71+
'btn-sm': size === 'sm',
72+
'btn-md': size === 'md',
73+
'btn-lg': size === 'lg',
74+
},
75+
cls
76+
)}
77+
>
1178
<Slot />
1279
</HeadlessButton>
1380
);

packages/shared/src/index.ts

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1 @@
1+
export * from './utils/clsq';

packages/shared/src/utils/clsq.ts

Lines changed: 55 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,55 @@
1+
/**
2+
* Custom version of 'clsx' utility migrated to TypeScript.
3+
*/
4+
5+
export type ClassDictionary = Record<string, any>;
6+
export type ClassArray = ClassValue[];
7+
export type ClassValue = ClassArray | ClassDictionary | string | number | null | boolean | undefined;
8+
9+
function toVal(mix: ClassValue) {
10+
let str = '';
11+
12+
if (typeof mix === 'string' || typeof mix === 'number') {
13+
str += mix;
14+
} else if (typeof mix === 'object') {
15+
if (Array.isArray(mix)) {
16+
for (let k=0; k < mix.length; k++) {
17+
if (mix[k]) {
18+
const y = toVal(mix[k])
19+
if (y) {
20+
str && (str += ' ');
21+
str += y;
22+
}
23+
}
24+
}
25+
} else {
26+
for (const k in mix) {
27+
if (mix[k]) {
28+
str && (str += ' ');
29+
str += k;
30+
}
31+
}
32+
}
33+
}
34+
35+
return str;
36+
}
37+
38+
export function clsq(...inputs: ClassValue[]) {
39+
let i = 0;
40+
let tmp;
41+
let str = '';
42+
while (i < inputs.length) {
43+
tmp = inputs[i++];
44+
if (tmp) {
45+
const x = toVal(tmp)
46+
if (x) {
47+
str && (str += ' ');
48+
str += x
49+
}
50+
}
51+
}
52+
return str;
53+
}
54+
55+
export default clsq;

packages/website/src/routes/docs/daisy/button/index.tsx

Lines changed: 74 additions & 11 deletions
Original file line numberDiff line numberDiff line change
@@ -1,27 +1,90 @@
1-
import { component$, $ } from '@builder.io/qwik';
1+
import { component$, $, useStylesScoped$ } from '@builder.io/qwik';
22
import { Button } from '@qwik-ui/theme-daisy';
33

44
export default component$(() => {
5+
useStylesScoped$(`
6+
.panel {
7+
display: flex;
8+
gap: 8px;
9+
flex-wrap: wrap;
10+
}`
11+
);
12+
513
return (
614
<>
715
<h2>This is the documentation for the Button</h2>
816

9-
<div className="flex flex-col gap-8 mt-4">
10-
<div>
11-
<h2>Basic Example</h2>
12-
<Button>SIMPLE BUTTON</Button>
17+
<div class="flex flex-col gap-8 mt-4">
18+
<h2>Basic Example</h2>
19+
<div class="panel">
20+
<Button>default</Button>
21+
<Button primary>primary</Button>
22+
<Button secondary>secondary</Button>
23+
<Button accent>accent</Button>
24+
<Button info>info</Button>
25+
<Button success>success</Button>
26+
<Button warning>warning</Button>
27+
<Button error>error</Button>
28+
<Button ghost>ghost</Button>
29+
<Button link>link</Button>
30+
<Button primary active>primary active</Button>
31+
<Button accent active>accent active</Button>
32+
<Button disabled>disabled</Button>
33+
<Button disabled={true}>disabled</Button>
1334
</div>
1435

15-
<div>
16-
<h2>Attributes</h2>
17-
<Button type="button" disabled={true}>
18-
DISABLED BUTTON
36+
<h2>Outline Example</h2>
37+
<div class="panel">
38+
<Button outline primary>primary</Button>
39+
<Button outline secondary>secondary</Button>
40+
<Button outline accent>accent</Button>
41+
<Button outline info>info</Button>
42+
<Button outline success>success</Button>
43+
<Button outline warning>warning</Button>
44+
<Button outline error>error</Button>
45+
<Button outline ghost>ghost</Button>
46+
<Button outline link>link</Button>
47+
<Button outline active>active</Button>
48+
<Button outline disabled>disabled</Button>
49+
</div>
50+
51+
<h2>size</h2>
52+
<div class="panel">
53+
<Button primary size="xs">xs</Button>
54+
<Button primary size="sm">sm</Button>
55+
<Button primary size="md">md</Button>
56+
<Button primary size="lg">lg</Button>
57+
</div>
58+
59+
<h2>loading</h2>
60+
<div class="panel">
61+
<Button primary loading>loading</Button>
62+
<Button loading square></Button>
63+
</div>
64+
65+
<h2>no click animation</h2>
66+
<div class="panel">
67+
<Button primary noAnimation>click me</Button>
68+
<Button secondary noAnimation>click me</Button>
69+
</div>
70+
71+
<h2>Square and Circle</h2>
72+
<div class="panel">
73+
<Button secondary square>A</Button>
74+
<Button accent circle>B</Button>
75+
</div>
76+
77+
<h2>Custom class</h2>
78+
79+
<div class="panel">
80+
<Button type="button" primary class="px-32 border-4 border-black">
81+
CUSTOM CLASS
1982
</Button>
2083
</div>
2184

2285
<div>
23-
<h2>Events</h2>
24-
<Button onClick$={$(() => window.alert('hello'))}>SHOW ALERT</Button>
86+
<h2>Qwik Events</h2>
87+
<Button primary onClick$={$(() => window.alert('hello'))}>SHOW ALERT</Button>
2588
</div>
2689
</div>
2790
</>
Lines changed: 9 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,9 @@
1+
.customCls {
2+
background-color: lightcoral;
3+
color: black;
4+
padding: 10px
5+
}
6+
7+
.customCls:hover {
8+
background-color: coral;
9+
}

packages/website/src/routes/docs/headless/button/index.tsx

Lines changed: 12 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -1,9 +1,12 @@
1-
import { $, component$ } from '@builder.io/qwik';
1+
import { $, component$, useStyles$ } from '@builder.io/qwik';
22
import { Button } from '@qwik-ui/headless';
3+
import styles from './index.css?inline';
34

45
export default component$(() => {
6+
useStyles$(styles);
7+
58
return (
6-
<>
9+
<div class="flex flex-col gap-8 mt-4">
710
<h2>This is the documentation for the Button</h2>
811
<div className="flex flex-col gap-8 mt-4">
912
<div>
@@ -18,11 +21,17 @@ export default component$(() => {
1821
</Button>
1922
</div>
2023

24+
<div>
25+
<h2>Custom styling</h2>
26+
<Button class="customCls">Custom Class</Button>
27+
<Button style="color: red">Custom styles</Button>
28+
</div>
29+
2130
<div>
2231
<h2>Events</h2>
2332
<Button onClick$={$(() => window.alert('hello'))}>SHOW ALERT</Button>
2433
</div>
2534
</div>
26-
</>
35+
</div>
2736
);
2837
});

packages/website/src/routes/docs/index.tsx

Lines changed: 26 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -16,6 +16,32 @@ export default component$(() => {
1616
btn btn-primary drawer-button
1717
drawer-side
1818
drawer-overlay
19+
btn
20+
btn-primary
21+
btn-secondary
22+
btn-accent
23+
btn-info
24+
btn-success
25+
btn-warning
26+
btn-error
27+
btn-ghost
28+
btn-link
29+
btn-outline
30+
btn-active
31+
btn-disabled
32+
33+
glass
34+
loading
35+
no-animation
36+
37+
btn-xs
38+
btn-sm
39+
btn-md
40+
btn-lg
41+
btn-wide
42+
btn-block
43+
btn-circle
44+
btn-square
1945
`}
2046
/>
2147
</div>

tsconfig.base.json

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -16,6 +16,7 @@
1616
"baseUrl": ".",
1717
"paths": {
1818
"@qwik-ui/core": ["packages/core/src/index.ts"],
19+
"@qwik-ui/shared": ["packages/shared/src/index.ts"],
1920
"@qwik-ui/theme-daisy": ["packages/daisy/src/index.ts"],
2021
"@qwik-ui/headless": ["packages/headless/src/index.ts"]
2122
}

0 commit comments

Comments
 (0)