@granularjs/ui 0.1.0 → 0.1.2
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.
- package/dist/granular-ui.min.js +24 -16
- package/dist/granular-ui.min.js.map +3 -3
- package/package.json +1 -1
- package/src/components/Button.js +3 -1
- package/src/components/Card.js +17 -16
- package/src/components/Container.js +1 -0
- package/src/components/List.js +7 -1
- package/src/components/SegmentedControl.js +9 -9
- package/src/components/Tabs.js +4 -7
- package/src/components/Text.js +3 -1
- package/src/index.js +1 -1
- package/src/theme/styles.js +23 -15
- package/types/index.d.ts +1 -1
package/package.json
CHANGED
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
{
|
|
2
2
|
"name": "@granularjs/ui",
|
|
3
|
-
"version": "0.1.
|
|
3
|
+
"version": "0.1.2",
|
|
4
4
|
"description": "90+ production-ready UI components for Granular. Dark/light themes, CSS variables, accessible, zero dependencies beyond @granularjs/core.",
|
|
5
5
|
"type": "module",
|
|
6
6
|
"main": "./dist/granular-ui.min.js",
|
package/src/components/Button.js
CHANGED
|
@@ -2,7 +2,7 @@ import { Button as HtmlButton, Span, when, after} from '@granularjs/core';
|
|
|
2
2
|
import { cx, splitPropsChildren, resolveBool, classVar, classFlag } from '../utils.js';
|
|
3
3
|
|
|
4
4
|
export function Button(...args) {
|
|
5
|
-
const { props, children } = splitPropsChildren(args, { variant: 'filled', size: 'md' });
|
|
5
|
+
const { props, children } = splitPropsChildren(args, { variant: 'filled', size: 'md', justify: 'center' });
|
|
6
6
|
const {
|
|
7
7
|
variant,
|
|
8
8
|
size,
|
|
@@ -12,6 +12,7 @@ export function Button(...args) {
|
|
|
12
12
|
rightSection,
|
|
13
13
|
className,
|
|
14
14
|
disabled,
|
|
15
|
+
justify,
|
|
15
16
|
...rest
|
|
16
17
|
} = props;
|
|
17
18
|
|
|
@@ -24,6 +25,7 @@ export function Button(...args) {
|
|
|
24
25
|
className: cx(
|
|
25
26
|
'g-ui-button',
|
|
26
27
|
classVar('g-ui-button-variant-', variant, 'filled'),
|
|
28
|
+
classVar('g-ui-justify-', justify, 'center'),
|
|
27
29
|
classVar('g-ui-button-size-', size, 'md'),
|
|
28
30
|
classFlag('g-ui-button-full', fullWidth),
|
|
29
31
|
classFlag('g-ui-button-loading', loading),
|
package/src/components/Card.js
CHANGED
|
@@ -1,40 +1,41 @@
|
|
|
1
|
-
import { Div, list, when, after } from '@granularjs/core';
|
|
1
|
+
import { Div, list, when, after, Span } from '@granularjs/core';
|
|
2
2
|
import { cx, splitPropsChildren, classVar } from '../utils.js';
|
|
3
3
|
import { Button } from './Button.js';
|
|
4
4
|
|
|
5
5
|
export function Card(...args) {
|
|
6
6
|
const { props, children } = splitPropsChildren(args, { padding: 'md', radius: 'md', shadow: 'none', border: 'default' });
|
|
7
|
-
const { title, content, actions, border,
|
|
7
|
+
const { title, content, actions, border, padding, radius, shadow, className, style, ...rest } = props;
|
|
8
8
|
|
|
9
9
|
return Div(
|
|
10
|
+
{ style },
|
|
10
11
|
when(title, () => Div({ className: 'g-ui-card-title' }, title)),
|
|
11
12
|
when(content, () => Div({ className: 'g-ui-card-content' }, content)),
|
|
13
|
+
{
|
|
14
|
+
className: cx(
|
|
15
|
+
'g-ui-card',
|
|
16
|
+
classVar('g-ui-card-border-', border, 'md'),
|
|
17
|
+
classVar('g-ui-card-padding-', padding, 'md'),
|
|
18
|
+
classVar('g-ui-card-radius-', radius, 'md'),
|
|
19
|
+
classVar('g-ui-card-shadow-', shadow, 'md'),
|
|
20
|
+
className
|
|
21
|
+
),
|
|
22
|
+
...rest,
|
|
23
|
+
},
|
|
24
|
+
children,
|
|
12
25
|
when(actions, () => Div(
|
|
13
26
|
{ className: 'g-ui-card-actions' },
|
|
14
27
|
list(actions, (action) => Button(
|
|
15
28
|
{
|
|
16
29
|
className: 'g-ui-card-action',
|
|
17
|
-
onClick: (e) => action.
|
|
30
|
+
onClick: (e) => action.get().onClick?.(e),
|
|
18
31
|
leftSection: action.leftSection,
|
|
19
32
|
rightSection: action.rightSection,
|
|
20
33
|
size: after(action.size).compute(s => s || 'sm'),
|
|
21
34
|
variant: after(action.variant).compute(v => v || 'outline'),
|
|
22
|
-
...(action.
|
|
35
|
+
...(action.get().props || {}),
|
|
23
36
|
},
|
|
24
37
|
action.label
|
|
25
38
|
))
|
|
26
39
|
)),
|
|
27
|
-
{
|
|
28
|
-
className: cx(
|
|
29
|
-
'g-ui-card',
|
|
30
|
-
classVar('g-ui-card-border-', border, 'md'),
|
|
31
|
-
classVar('g-ui-card-padding-', padding, 'md'),
|
|
32
|
-
classVar('g-ui-card-radius-', radius, 'md'),
|
|
33
|
-
classVar('g-ui-card-shadow-', shadow, 'md'),
|
|
34
|
-
className
|
|
35
|
-
),
|
|
36
|
-
...rest,
|
|
37
|
-
},
|
|
38
|
-
children
|
|
39
40
|
);
|
|
40
41
|
}
|
package/src/components/List.js
CHANGED
|
@@ -17,7 +17,13 @@ export function List(...args) {
|
|
|
17
17
|
value && typeof value === 'object' && typeof value.tagName === 'string' &&
|
|
18
18
|
value.tagName.toLowerCase() === 'li';
|
|
19
19
|
const wrapChild = (child) => {
|
|
20
|
+
console.log('INFO ABOUT ITEM', child,
|
|
21
|
+
typeof child,
|
|
22
|
+
typeof child?.tagName,
|
|
23
|
+
child?.tagName?.toLowerCase()
|
|
24
|
+
);
|
|
20
25
|
const wrapValue = (value) => {
|
|
26
|
+
if (value?.nodeType === 'granular-list-node') return value;
|
|
21
27
|
if (value == null || value === false) return null;
|
|
22
28
|
if (Array.isArray(value)) return value.map((item) => wrapValue(item));
|
|
23
29
|
if (isListItemNode(value)) return value;
|
|
@@ -29,7 +35,7 @@ export function List(...args) {
|
|
|
29
35
|
}
|
|
30
36
|
return wrapValue(child);
|
|
31
37
|
};
|
|
32
|
-
const listChildren = children.map((child) => wrapChild(child));
|
|
38
|
+
const listChildren = when(children, () => children.map((child) => wrapChild(child)));
|
|
33
39
|
const listProps = {
|
|
34
40
|
...rest,
|
|
35
41
|
className: cx(
|
|
@@ -1,4 +1,4 @@
|
|
|
1
|
-
import { Div, after, state } from '@granularjs/core';
|
|
1
|
+
import { Div, after, state, list } from '@granularjs/core';
|
|
2
2
|
import { cx, splitPropsChildren, classVar, resolveValue } from '../utils.js';
|
|
3
3
|
|
|
4
4
|
export function SegmentedControl(...args) {
|
|
@@ -18,22 +18,22 @@ export function SegmentedControl(...args) {
|
|
|
18
18
|
return Div(
|
|
19
19
|
{ ...rest, className: cx(scroll && 'g-ui-segmented-scroll') },
|
|
20
20
|
Div(
|
|
21
|
-
{ className: cx('g-ui-segmented', classVar('g-ui-segmented-size-', size, 'sm'),
|
|
22
|
-
data
|
|
21
|
+
{ className: cx('g-ui-segmented', classVar('g-ui-segmented-size-', size, 'sm'), className) },
|
|
22
|
+
list(data, ((item) =>
|
|
23
23
|
Div(
|
|
24
24
|
{
|
|
25
25
|
className: cx(
|
|
26
26
|
'g-ui-segmented-item',
|
|
27
|
-
|
|
28
|
-
|
|
29
|
-
|
|
30
|
-
|
|
27
|
+
after(currentState).compute((current) => {
|
|
28
|
+
if (item.get().value === current) return 'g-ui-segmented-active';
|
|
29
|
+
return '';
|
|
30
|
+
})
|
|
31
31
|
),
|
|
32
|
-
onClick: () => setValue(item.value),
|
|
32
|
+
onClick: () => setValue(item.get().value),
|
|
33
33
|
},
|
|
34
34
|
item.label
|
|
35
35
|
)
|
|
36
|
-
)
|
|
36
|
+
))
|
|
37
37
|
)
|
|
38
38
|
);
|
|
39
39
|
}
|
package/src/components/Tabs.js
CHANGED
|
@@ -160,8 +160,7 @@ export function Tabs(...args) {
|
|
|
160
160
|
});
|
|
161
161
|
|
|
162
162
|
return Div(
|
|
163
|
-
Div(
|
|
164
|
-
{
|
|
163
|
+
Div({
|
|
165
164
|
className: cx(
|
|
166
165
|
'g-ui-tabs',
|
|
167
166
|
classMap(orientation, { vertical: 'g-ui-tabs-vertical' }),
|
|
@@ -171,22 +170,20 @@ export function Tabs(...args) {
|
|
|
171
170
|
},
|
|
172
171
|
Div({ node: sentinelNode }),
|
|
173
172
|
Div({ style: spacerStyle }),
|
|
174
|
-
Div(
|
|
175
|
-
{ node: listNode, className: 'g-ui-tabs-list', style: stickyStyle },
|
|
173
|
+
Div({ node: listNode, className: 'g-ui-tabs-list', style: stickyStyle },
|
|
176
174
|
list(tabs, (tab) =>
|
|
177
175
|
Button(
|
|
178
176
|
{
|
|
179
177
|
className: after(currentState, tab.value).compute(([v, tabVal]) =>
|
|
180
178
|
cx('g-ui-tabs-tab', tabVal === v && 'g-ui-tabs-tab-active')
|
|
181
179
|
),
|
|
182
|
-
onClick: () => setValue(tab.
|
|
180
|
+
onClick: () => setValue(tab.get().value),
|
|
183
181
|
},
|
|
184
182
|
tab.label
|
|
185
183
|
)
|
|
186
184
|
)
|
|
187
185
|
),
|
|
188
|
-
Div(
|
|
189
|
-
{ className: 'g-ui-tabs-panel' },
|
|
186
|
+
Div({ className: 'g-ui-tabs-panel' },
|
|
190
187
|
when(currentState, () => tabs.get()?.find((tab) => tab.value === currentState.get())?.content ?? null)
|
|
191
188
|
)
|
|
192
189
|
)
|
package/src/components/Text.js
CHANGED
|
@@ -3,7 +3,7 @@ import { cx, splitPropsChildren, classVar, classFlag, classMap } from '../utils.
|
|
|
3
3
|
|
|
4
4
|
export function Text(...args) {
|
|
5
5
|
const { props, children } = splitPropsChildren(args, { size: 'md' });
|
|
6
|
-
const { size, weight, color, dimmed, align, className, style, ...rest } = props;
|
|
6
|
+
const { size, weight, color, dimmed, align, ellipsis, className, style, ...rest } = props;
|
|
7
7
|
const weightClass = classMap(weight, {
|
|
8
8
|
bold: 'g-ui-text-weight-700',
|
|
9
9
|
semibold: 'g-ui-text-weight-600',
|
|
@@ -27,10 +27,12 @@ export function Text(...args) {
|
|
|
27
27
|
return Span(
|
|
28
28
|
{
|
|
29
29
|
...rest,
|
|
30
|
+
style,
|
|
30
31
|
className: cx(
|
|
31
32
|
'g-ui-text',
|
|
32
33
|
classVar('g-ui-text-size-', size, 'md'),
|
|
33
34
|
classFlag('g-ui-text-dimmed', dimmed),
|
|
35
|
+
classFlag('g-ui-text-ellipsis', ellipsis),
|
|
34
36
|
weightClass,
|
|
35
37
|
colorClass,
|
|
36
38
|
alignClass,
|
package/src/index.js
CHANGED
|
@@ -3,7 +3,7 @@ import { ensureStyles } from './theme/styles.js';
|
|
|
3
3
|
ensureStyles();
|
|
4
4
|
|
|
5
5
|
export { setThemeVars, setThemeMode } from './theme/theme.js';
|
|
6
|
-
export { cx } from './utils.js';
|
|
6
|
+
export { cx, classVar, classFlag, classMap, splitPropsChildren } from './utils.js';
|
|
7
7
|
export { Button } from './components/Button.js';
|
|
8
8
|
export { Text } from './components/Text.js';
|
|
9
9
|
export { Title } from './components/Title.js';
|
package/src/theme/styles.js
CHANGED
|
@@ -819,7 +819,6 @@ body {
|
|
|
819
819
|
line-height: 1;
|
|
820
820
|
display: inline-flex;
|
|
821
821
|
align-items: center;
|
|
822
|
-
justify-content: center;
|
|
823
822
|
}
|
|
824
823
|
.g-ui-button:active { transform: translateY(1px); }
|
|
825
824
|
.g-ui-button:disabled { opacity: 0.6; cursor: not-allowed; }
|
|
@@ -840,8 +839,8 @@ body {
|
|
|
840
839
|
.g-ui-button-size-xs { font-size: 12px; height: 30px; padding: 0 var(--g-ui-space-8); }
|
|
841
840
|
.g-ui-button-size-sm { font-size: 13px; height: 36px; padding: 0 var(--g-ui-space-10); }
|
|
842
841
|
.g-ui-button-size-md { font-size: 14px; height: 42px; padding: 0 var(--g-ui-space-10); }
|
|
843
|
-
.g-ui-button-size-lg { font-size: 15px; height: 50px; padding: 0 var(--g-ui-space-
|
|
844
|
-
.g-ui-button-size-xl { font-size: 16px; height: 60px; padding: 0 var(--g-ui-space-
|
|
842
|
+
.g-ui-button-size-lg { font-size: 15px; height: 50px; padding: 0 var(--g-ui-space-12); }
|
|
843
|
+
.g-ui-button-size-xl { font-size: 16px; height: 60px; padding: 0 var(--g-ui-space-14); }
|
|
845
844
|
|
|
846
845
|
.g-ui-input-wrapper {
|
|
847
846
|
width: 100%;
|
|
@@ -896,6 +895,11 @@ body {
|
|
|
896
895
|
flex-direction: column;
|
|
897
896
|
gap: var(--g-ui-space-6);
|
|
898
897
|
}
|
|
898
|
+
.g-ui-text-ellipsis {
|
|
899
|
+
overflow: hidden;
|
|
900
|
+
text-overflow: ellipsis;
|
|
901
|
+
white-space: nowrap;
|
|
902
|
+
}
|
|
899
903
|
.g-ui-text-input-label {
|
|
900
904
|
font-size: 13px;
|
|
901
905
|
font-weight: 500;
|
|
@@ -961,6 +965,9 @@ body {
|
|
|
961
965
|
padding: 0;
|
|
962
966
|
width: 28px;
|
|
963
967
|
height: 28px;
|
|
968
|
+
display: flex;
|
|
969
|
+
align-items: center;
|
|
970
|
+
justify-content: center;
|
|
964
971
|
}
|
|
965
972
|
.g-ui-modal-close svg {
|
|
966
973
|
width: 16px;
|
|
@@ -1000,6 +1007,7 @@ body {
|
|
|
1000
1007
|
background: var(--g-ui-bg);
|
|
1001
1008
|
position: relative;
|
|
1002
1009
|
transition: background-color .12s ease, border-color .12s ease;
|
|
1010
|
+
cursor: pointer;
|
|
1003
1011
|
}
|
|
1004
1012
|
.g-ui-checkbox-input:focus-visible {
|
|
1005
1013
|
outline: 2px solid var(--g-ui-primary);
|
|
@@ -1026,22 +1034,22 @@ body {
|
|
|
1026
1034
|
.g-ui-checkbox-size-xs .g-ui-checkbox-indeterminate svg { width: 16px; height: 16px; }
|
|
1027
1035
|
.g-ui-checkbox-size-sm .g-ui-checkbox-indeterminate { top:3px; left:4px; }
|
|
1028
1036
|
.g-ui-checkbox-size-sm .g-ui-checkbox-indeterminate svg { width: 20px; height:20px; }
|
|
1029
|
-
.g-ui-checkbox-size-md .g-ui-checkbox-indeterminate { top:
|
|
1037
|
+
.g-ui-checkbox-size-md .g-ui-checkbox-indeterminate { top:0px; left:0px; }
|
|
1030
1038
|
.g-ui-checkbox-size-md .g-ui-checkbox-indeterminate svg { width: 24px; height: 24px; }
|
|
1031
1039
|
.g-ui-checkbox-size-lg .g-ui-checkbox-indeterminate { top:4px; left:5px; }
|
|
1032
1040
|
.g-ui-checkbox-size-lg .g-ui-checkbox-indeterminate svg { width: 28px; height: 28px; }
|
|
1033
1041
|
.g-ui-checkbox-size-xl .g-ui-checkbox-indeterminate { top:5px; left:6px; }
|
|
1034
1042
|
.g-ui-checkbox-size-xl .g-ui-checkbox-indeterminate svg { width: 32px; height: 32px; }
|
|
1035
1043
|
|
|
1036
|
-
.g-ui-checkbox-size-xs .g-ui-checkbox-checked { top:
|
|
1044
|
+
.g-ui-checkbox-size-xs .g-ui-checkbox-checked { top: 0px;left:0.5px; }
|
|
1037
1045
|
.g-ui-checkbox-size-xs .g-ui-checkbox-checked svg { width: 16px; height: 16px; }
|
|
1038
|
-
.g-ui-checkbox-size-sm .g-ui-checkbox-checked { top:
|
|
1046
|
+
.g-ui-checkbox-size-sm .g-ui-checkbox-checked { top:0px; left:0.3px; }
|
|
1039
1047
|
.g-ui-checkbox-size-sm .g-ui-checkbox-checked svg { width: 20px; height:20px; }
|
|
1040
|
-
.g-ui-checkbox-size-md .g-ui-checkbox-checked { top:
|
|
1048
|
+
.g-ui-checkbox-size-md .g-ui-checkbox-checked { top:0px; left:0px; }
|
|
1041
1049
|
.g-ui-checkbox-size-md .g-ui-checkbox-checked svg { width: 24px; height: 24px; }
|
|
1042
|
-
.g-ui-checkbox-size-lg .g-ui-checkbox-checked { top:
|
|
1050
|
+
.g-ui-checkbox-size-lg .g-ui-checkbox-checked { top:1px; left:1px; }
|
|
1043
1051
|
.g-ui-checkbox-size-lg .g-ui-checkbox-checked svg { width: 28px; height: 28px; }
|
|
1044
|
-
.g-ui-checkbox-size-xl .g-ui-checkbox-checked { top:
|
|
1052
|
+
.g-ui-checkbox-size-xl .g-ui-checkbox-checked { top:2px; left:3px; }
|
|
1045
1053
|
.g-ui-checkbox-size-xl .g-ui-checkbox-checked svg { width: 32px; height: 32px; }
|
|
1046
1054
|
|
|
1047
1055
|
.g-ui-switch {
|
|
@@ -1080,14 +1088,14 @@ body {
|
|
|
1080
1088
|
border-color: var(--g-ui-primary);
|
|
1081
1089
|
}
|
|
1082
1090
|
.g-ui-switch-input:checked::after {
|
|
1083
|
-
transform: translateX(calc(var(--g-ui-switch-width, 36px) - var(--g-ui-switch-thumb, 14px) - (var(--g-ui-switch-offset, 2px) * 2)));
|
|
1091
|
+
transform: translateX(calc(var(--g-ui-switch-width, 36px) - var(--g-ui-switch-thumb, 14px) - (var(--g-ui-switch-offset, 2px) * 2) - 2px));
|
|
1084
1092
|
}
|
|
1085
1093
|
.g-ui-switch-label { font-size: 14px; }
|
|
1086
|
-
.g-ui-switch-size-xs { --g-ui-switch-width: 32px; --g-ui-switch-height: 16px; --g-ui-switch-thumb: 12px; --g-ui-switch-offset:
|
|
1087
|
-
.g-ui-switch-size-sm { --g-ui-switch-width: 38px; --g-ui-switch-height: 20px; --g-ui-switch-thumb: 14px; --g-ui-switch-offset:
|
|
1088
|
-
.g-ui-switch-size-md { --g-ui-switch-width: 46px; --g-ui-switch-height: 24px; --g-ui-switch-thumb: 18px; --g-ui-switch-offset:
|
|
1089
|
-
.g-ui-switch-size-lg { --g-ui-switch-width: 56px; --g-ui-switch-height: 30px; --g-ui-switch-thumb: 22px; --g-ui-switch-offset:
|
|
1090
|
-
.g-ui-switch-size-xl { --g-ui-switch-width: 72px; --g-ui-switch-height: 36px; --g-ui-switch-thumb: 28px; --g-ui-switch-offset:
|
|
1094
|
+
.g-ui-switch-size-xs { --g-ui-switch-width: 32px; --g-ui-switch-height: 16px; --g-ui-switch-thumb: 12px; --g-ui-switch-offset: 1px; }
|
|
1095
|
+
.g-ui-switch-size-sm { --g-ui-switch-width: 38px; --g-ui-switch-height: 20px; --g-ui-switch-thumb: 14px; --g-ui-switch-offset: 2px; }
|
|
1096
|
+
.g-ui-switch-size-md { --g-ui-switch-width: 46px; --g-ui-switch-height: 24px; --g-ui-switch-thumb: 18px; --g-ui-switch-offset: 2px; }
|
|
1097
|
+
.g-ui-switch-size-lg { --g-ui-switch-width: 56px; --g-ui-switch-height: 30px; --g-ui-switch-thumb: 22px; --g-ui-switch-offset: 3px; }
|
|
1098
|
+
.g-ui-switch-size-xl { --g-ui-switch-width: 72px; --g-ui-switch-height: 36px; --g-ui-switch-thumb: 28px; --g-ui-switch-offset: 3px; }
|
|
1091
1099
|
|
|
1092
1100
|
.g-ui-select-root {
|
|
1093
1101
|
position: relative;
|
package/types/index.d.ts
CHANGED
|
@@ -1,4 +1,3 @@
|
|
|
1
|
-
export { cx } from "./utils.js";
|
|
2
1
|
export { Button } from "./components/Button.js";
|
|
3
2
|
export { Text } from "./components/Text.js";
|
|
4
3
|
export { Title } from "./components/Title.js";
|
|
@@ -91,3 +90,4 @@ export { BottomBar } from "./components/BottomBar.js";
|
|
|
91
90
|
export { EventCalendar } from "./components/EventCalendar.js";
|
|
92
91
|
export { useDisclosure } from "./hooks/useDisclosure.js";
|
|
93
92
|
export { setThemeVars, setThemeMode } from "./theme/theme.js";
|
|
93
|
+
export { cx, classVar, classFlag, classMap, splitPropsChildren } from "./utils.js";
|