@stack-spot/citric-react 0.26.0 → 0.27.1
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/citric.css +54 -3
- package/dist/components/CheckboxGroup.d.ts +15 -1
- package/dist/components/CheckboxGroup.d.ts.map +1 -1
- package/dist/components/CheckboxGroup.js +5 -3
- package/dist/components/CheckboxGroup.js.map +1 -1
- package/dist/components/CitricComponent.d.ts +1 -1
- package/dist/components/CitricComponent.d.ts.map +1 -1
- package/dist/components/RadioGroup.d.ts +13 -1
- package/dist/components/RadioGroup.d.ts.map +1 -1
- package/dist/components/RadioGroup.js +3 -3
- package/dist/components/RadioGroup.js.map +1 -1
- package/dist/components/Select/MultiSelect.d.ts +60 -0
- package/dist/components/Select/MultiSelect.d.ts.map +1 -0
- package/dist/components/Select/MultiSelect.js +84 -0
- package/dist/components/Select/MultiSelect.js.map +1 -0
- package/dist/components/Select/RichSelect.d.ts +1 -1
- package/dist/components/Select/RichSelect.d.ts.map +1 -1
- package/dist/components/Select/RichSelect.js +14 -112
- package/dist/components/Select/RichSelect.js.map +1 -1
- package/dist/components/Select/hooks.d.ts +23 -0
- package/dist/components/Select/hooks.d.ts.map +1 -0
- package/dist/components/Select/hooks.js +114 -0
- package/dist/components/Select/hooks.js.map +1 -0
- package/dist/components/Select/types.d.ts +16 -5
- package/dist/components/Select/types.d.ts.map +1 -1
- package/dist/index.d.ts +1 -0
- package/dist/index.d.ts.map +1 -1
- package/dist/index.js +1 -0
- package/dist/index.js.map +1 -1
- package/dist/utils/checkbox.js +1 -1
- package/dist/utils/checkbox.js.map +1 -1
- package/package.json +1 -1
- package/src/components/CheckboxGroup.tsx +18 -1
- package/src/components/CitricComponent.ts +1 -1
- package/src/components/RadioGroup.tsx +16 -1
- package/src/components/Select/MultiSelect.tsx +205 -0
- package/src/components/Select/RichSelect.tsx +16 -109
- package/src/components/Select/hooks.ts +133 -0
- package/src/components/Select/types.ts +16 -5
- package/src/index.ts +1 -0
- package/src/utils/checkbox.ts +1 -1
package/dist/citric.css
CHANGED
|
@@ -1118,7 +1118,8 @@ input[type="range"][data-citric="slider"] {
|
|
|
1118
1118
|
|
|
1119
1119
|
/* Parts of the select css is in input.css. */
|
|
1120
1120
|
|
|
1121
|
-
[data-citric="rich-select"]
|
|
1121
|
+
[data-citric="rich-select"],
|
|
1122
|
+
[data-citric="multi-select"] {
|
|
1122
1123
|
--default-padding: 4px 8px;
|
|
1123
1124
|
--default-max-height: 300px;
|
|
1124
1125
|
--animation-duration: 0.3s;
|
|
@@ -1184,6 +1185,9 @@ input[type="range"][data-citric="slider"] {
|
|
|
1184
1185
|
pointer-events: none;
|
|
1185
1186
|
transition: transform var(--animation-duration) ease-in;
|
|
1186
1187
|
}
|
|
1188
|
+
.placeholder {
|
|
1189
|
+
color: var(--light-700);
|
|
1190
|
+
}
|
|
1187
1191
|
}
|
|
1188
1192
|
&:has(.search-bar) header {
|
|
1189
1193
|
min-width: 150px;
|
|
@@ -1221,7 +1225,7 @@ input[type="range"][data-citric="slider"] {
|
|
|
1221
1225
|
}
|
|
1222
1226
|
}
|
|
1223
1227
|
|
|
1224
|
-
|
|
1228
|
+
> .options {
|
|
1225
1229
|
margin: 0;
|
|
1226
1230
|
padding: 0;
|
|
1227
1231
|
list-style: none;
|
|
@@ -1229,7 +1233,7 @@ input[type="range"][data-citric="slider"] {
|
|
|
1229
1233
|
flex-direction: column;
|
|
1230
1234
|
flex: 1;
|
|
1231
1235
|
overflow: hidden;
|
|
1232
|
-
|
|
1236
|
+
> .option {
|
|
1233
1237
|
padding: var(--padding, var(--default-padding));
|
|
1234
1238
|
display: flex;
|
|
1235
1239
|
transition: background-color 0.3s;
|
|
@@ -1554,6 +1558,52 @@ input[type="range"][data-citric="slider"] {
|
|
|
1554
1558
|
}
|
|
1555
1559
|
|
|
1556
1560
|
|
|
1561
|
+
/* Parts of the multi-select css is in input.css. */
|
|
1562
|
+
|
|
1563
|
+
[data-citric="multi-select"] {
|
|
1564
|
+
--default-padding: 8px;
|
|
1565
|
+
header {
|
|
1566
|
+
outline: none;
|
|
1567
|
+
&:not(.custom) {
|
|
1568
|
+
> span, > .row {
|
|
1569
|
+
overflow: hidden;
|
|
1570
|
+
white-space: nowrap;
|
|
1571
|
+
text-overflow: ellipsis;
|
|
1572
|
+
}
|
|
1573
|
+
> .row {
|
|
1574
|
+
position: relative;
|
|
1575
|
+
&:after {
|
|
1576
|
+
content: '';
|
|
1577
|
+
position: absolute;
|
|
1578
|
+
top: 0;
|
|
1579
|
+
bottom: 0;
|
|
1580
|
+
right: 0;
|
|
1581
|
+
width: 50px;
|
|
1582
|
+
pointer-events: none;
|
|
1583
|
+
background: linear-gradient(90deg, transparent 0%, var(--light-300) 100%);;
|
|
1584
|
+
}
|
|
1585
|
+
}
|
|
1586
|
+
}
|
|
1587
|
+
}
|
|
1588
|
+
[data-citric="checkbox-row"] {
|
|
1589
|
+
gap: 8px;
|
|
1590
|
+
}
|
|
1591
|
+
label {
|
|
1592
|
+
width: 100%;
|
|
1593
|
+
cursor: pointer;
|
|
1594
|
+
}
|
|
1595
|
+
input[type="checkbox"] {
|
|
1596
|
+
outline: none;
|
|
1597
|
+
}
|
|
1598
|
+
.option.unfiltered {
|
|
1599
|
+
opacity: 0.5;
|
|
1600
|
+
}
|
|
1601
|
+
.select-all {
|
|
1602
|
+
padding: var(--padding, var(--default-padding));
|
|
1603
|
+
}
|
|
1604
|
+
}
|
|
1605
|
+
|
|
1606
|
+
|
|
1557
1607
|
[data-citric="menu"] {
|
|
1558
1608
|
--bg: var(--light-300);
|
|
1559
1609
|
--hover-bg: var(--light-500);
|
|
@@ -1721,6 +1771,7 @@ nav[data-citric="menu"].rounded-items, [data-citric="menu"].rounded-items nav {
|
|
|
1721
1771
|
[data-citric="input"],
|
|
1722
1772
|
[data-citric="select"] select,
|
|
1723
1773
|
[data-citric="rich-select"],
|
|
1774
|
+
[data-citric="multi-select"],
|
|
1724
1775
|
[data-citric="textarea"] {
|
|
1725
1776
|
height: 2.5rem;
|
|
1726
1777
|
padding: var(--spacing-3);
|
|
@@ -61,6 +61,18 @@ export interface BaseCheckboxGroupProps<T = any> extends WithColorScheme {
|
|
|
61
61
|
* @returns true if the item should be disabled, false otherwise.
|
|
62
62
|
*/
|
|
63
63
|
isDisabled?: (option: T) => boolean;
|
|
64
|
+
/**
|
|
65
|
+
* The space between options.
|
|
66
|
+
*
|
|
67
|
+
* @default "8px"
|
|
68
|
+
*/
|
|
69
|
+
gap?: string;
|
|
70
|
+
/**
|
|
71
|
+
* If set to false, the checkboxes will have tabIndex = -1.
|
|
72
|
+
*
|
|
73
|
+
* @default true
|
|
74
|
+
*/
|
|
75
|
+
focusable?: boolean;
|
|
64
76
|
}
|
|
65
77
|
export type CheckboxGroupProps<T> = Omit<React.JSX.IntrinsicElements['div'], 'onChange' | 'children'> & BaseCheckboxGroupProps<T>;
|
|
66
78
|
/**
|
|
@@ -70,6 +82,8 @@ export type CheckboxGroupProps<T> = Omit<React.JSX.IntrinsicElements['div'], 'on
|
|
|
70
82
|
*
|
|
71
83
|
* Tip: if you need to implement features like "search" and "select all", use the hook `useCheckboxGroupControls`.
|
|
72
84
|
*
|
|
85
|
+
* Tip: If you need a checkbox group that doesn't occupy much height, consider using a MultiSelect.
|
|
86
|
+
*
|
|
73
87
|
* @example
|
|
74
88
|
*
|
|
75
89
|
* ```
|
|
@@ -84,5 +98,5 @@ export type CheckboxGroupProps<T> = Omit<React.JSX.IntrinsicElements['div'], 'on
|
|
|
84
98
|
* return <CheckboxGroup options={options} renderLabel={o => o.name} renderKey={o => o.id} value={value} setValue={setValue} />
|
|
85
99
|
* ```
|
|
86
100
|
*/
|
|
87
|
-
export declare const CheckboxGroup: <T>({ appearance, name, value, options, onChange, renderLabel, renderKey, renderItem, isDisabled, colorScheme, style, ...props }: CheckboxGroupProps<T>) => import("react/jsx-runtime").JSX.Element;
|
|
101
|
+
export declare const CheckboxGroup: <T>({ appearance, name, value, options, onChange, renderLabel, renderKey, renderItem, isDisabled, colorScheme, style, gap, focusable, ...props }: CheckboxGroupProps<T>) => import("react/jsx-runtime").JSX.Element;
|
|
88
102
|
//# sourceMappingURL=CheckboxGroup.d.ts.map
|
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"CheckboxGroup.d.ts","sourceRoot":"","sources":["../../src/components/CheckboxGroup.tsx"],"names":[],"mappings":"AAEA,OAAO,EAAE,eAAe,EAAE,MAAM,UAAU,CAAA;AAM1C,MAAM,WAAW,sBAAsB,CAAC,CAAC,GAAG,GAAG,CAAE,SAAQ,eAAe;IACtE;;;OAGG;IACH,UAAU,CAAC,EAAE,UAAU,GAAG,QAAQ,CAAC;IACnC;;OAEG;IACH,IAAI,CAAC,EAAE,MAAM,CAAC;IACd;;OAEG;IACH,KAAK,EAAE,CAAC,EAAE,CAAC;IACX;;OAEG;IACH,OAAO,EAAE,CAAC,EAAE,CAAC;IACb;;;OAGG;IACH,QAAQ,EAAE,CAAC,KAAK,EAAE,CAAC,EAAE,KAAK,IAAI,CAAC;IAC/B;;;;;;;;;;OAUG;IACH,WAAW,CAAC,EAAE,CAAC,MAAM,EAAE,CAAC,KAAK,KAAK,CAAC,SAAS,CAAC;IAC7C;;;;;;;;;OASG;IACH,UAAU,CAAC,EAAE,CAAC,QAAQ,EAAE,KAAK,CAAC,YAAY,EAAE,MAAM,EAAE,CAAC,KAAK,KAAK,CAAC,SAAS,CAAC;IAC1E;;;;;;;OAOG;IACH,SAAS,CAAC,EAAE,CAAC,MAAM,EAAE,CAAC,KAAK,MAAM,GAAG,MAAM,GAAG,SAAS,CAAC;IACvD;;;;;OAKG;IACH,UAAU,CAAC,EAAE,CAAC,MAAM,EAAE,CAAC,KAAK,OAAO,CAAC;
|
|
1
|
+
{"version":3,"file":"CheckboxGroup.d.ts","sourceRoot":"","sources":["../../src/components/CheckboxGroup.tsx"],"names":[],"mappings":"AAEA,OAAO,EAAE,eAAe,EAAE,MAAM,UAAU,CAAA;AAM1C,MAAM,WAAW,sBAAsB,CAAC,CAAC,GAAG,GAAG,CAAE,SAAQ,eAAe;IACtE;;;OAGG;IACH,UAAU,CAAC,EAAE,UAAU,GAAG,QAAQ,CAAC;IACnC;;OAEG;IACH,IAAI,CAAC,EAAE,MAAM,CAAC;IACd;;OAEG;IACH,KAAK,EAAE,CAAC,EAAE,CAAC;IACX;;OAEG;IACH,OAAO,EAAE,CAAC,EAAE,CAAC;IACb;;;OAGG;IACH,QAAQ,EAAE,CAAC,KAAK,EAAE,CAAC,EAAE,KAAK,IAAI,CAAC;IAC/B;;;;;;;;;;OAUG;IACH,WAAW,CAAC,EAAE,CAAC,MAAM,EAAE,CAAC,KAAK,KAAK,CAAC,SAAS,CAAC;IAC7C;;;;;;;;;OASG;IACH,UAAU,CAAC,EAAE,CAAC,QAAQ,EAAE,KAAK,CAAC,YAAY,EAAE,MAAM,EAAE,CAAC,KAAK,KAAK,CAAC,SAAS,CAAC;IAC1E;;;;;;;OAOG;IACH,SAAS,CAAC,EAAE,CAAC,MAAM,EAAE,CAAC,KAAK,MAAM,GAAG,MAAM,GAAG,SAAS,CAAC;IACvD;;;;;OAKG;IACH,UAAU,CAAC,EAAE,CAAC,MAAM,EAAE,CAAC,KAAK,OAAO,CAAC;IACpC;;;;OAIG;IACH,GAAG,CAAC,EAAE,MAAM,CAAC;IACb;;;;OAIG;IACH,SAAS,CAAC,EAAE,OAAO,CAAC;CACrB;AAED,MAAM,MAAM,kBAAkB,CAAC,CAAC,IAAI,IAAI,CAAC,KAAK,CAAC,GAAG,CAAC,iBAAiB,CAAC,KAAK,CAAC,EAAE,UAAU,GAAG,UAAU,CAAC,GAAG,sBAAsB,CAAC,CAAC,CAAC,CAAA;AAEjI;;;;;;;;;;;;;;;;;;;;;;GAsBG;AACH,eAAO,MAAM,aAAa,GACD,CAAC,gJAerB,kBAAkB,CAAC,CAAC,CAAC,4CA0BzB,CAAA"}
|
|
@@ -12,6 +12,8 @@ import { Column } from './layout.js';
|
|
|
12
12
|
*
|
|
13
13
|
* Tip: if you need to implement features like "search" and "select all", use the hook `useCheckboxGroupControls`.
|
|
14
14
|
*
|
|
15
|
+
* Tip: If you need a checkbox group that doesn't occupy much height, consider using a MultiSelect.
|
|
16
|
+
*
|
|
15
17
|
* @example
|
|
16
18
|
*
|
|
17
19
|
* ```
|
|
@@ -26,15 +28,15 @@ import { Column } from './layout.js';
|
|
|
26
28
|
* return <CheckboxGroup options={options} renderLabel={o => o.name} renderKey={o => o.id} value={value} setValue={setValue} />
|
|
27
29
|
* ```
|
|
28
30
|
*/
|
|
29
|
-
export const CheckboxGroup = withRef(function CheckboxGroup({ appearance = 'checkbox', name, value = [], options, onChange, renderLabel = defaultRenderLabel, renderKey = defaultRenderKey, renderItem, isDisabled, colorScheme, style, ...props }) {
|
|
31
|
+
export const CheckboxGroup = withRef(function CheckboxGroup({ appearance = 'checkbox', name, value = [], options, onChange, renderLabel = defaultRenderLabel, renderKey = defaultRenderKey, renderItem, isDisabled, colorScheme, style, gap = '8px', focusable = true, ...props }) {
|
|
30
32
|
const items = useMemo(() => {
|
|
31
33
|
const valueKeys = value.map(renderKey);
|
|
32
34
|
return options.map((o) => {
|
|
33
35
|
const key = renderKey(o);
|
|
34
|
-
const checkbox = _jsx(CitricComponent, { tag: "input", component: appearance, type: "checkbox", name: name, value: key, checked: value.includes(o) || (!isNil(key) && valueKeys.includes(key)), onChange: (e) => onChange?.(e.target.checked ? [...(value ?? []), o] : (value?.filter(item => item != o) ?? [])), disabled: isDisabled?.(o) });
|
|
36
|
+
const checkbox = _jsx(CitricComponent, { tag: "input", component: appearance, type: "checkbox", name: name, value: key, checked: value.includes(o) || (!isNil(key) && valueKeys.includes(key)), onChange: (e) => onChange?.(e.target.checked ? [...(value ?? []), o] : (value?.filter(item => item != o) ?? [])), disabled: isDisabled?.(o), tabIndex: focusable ? undefined : -1 });
|
|
35
37
|
return renderItem ? renderItem(checkbox, o) : (_jsxs(CitricComponent, { tag: "label", component: `${appearance}-row`, colorScheme: colorScheme, children: [checkbox, renderLabel(o)] }, key));
|
|
36
38
|
});
|
|
37
39
|
}, [options, value, name, colorScheme, appearance]);
|
|
38
|
-
return _jsx(Column, { ...props, style: { gap
|
|
40
|
+
return _jsx(Column, { ...props, style: { gap, ...style }, children: items });
|
|
39
41
|
});
|
|
40
42
|
//# sourceMappingURL=CheckboxGroup.js.map
|
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"CheckboxGroup.js","sourceRoot":"","sources":["../../src/components/CheckboxGroup.tsx"],"names":[],"mappings":";AAAA,OAAO,EAAE,KAAK,EAAE,MAAM,QAAQ,CAAA;AAC9B,OAAO,EAAE,OAAO,EAAE,MAAM,OAAO,CAAA;AAE/B,OAAO,EAAE,gBAAgB,EAAE,kBAAkB,EAAE,MAAM,kBAAkB,CAAA;AACvE,OAAO,EAAE,OAAO,EAAE,MAAM,gBAAgB,CAAA;AACxC,OAAO,EAAE,eAAe,EAAE,MAAM,mBAAmB,CAAA;AACnD,OAAO,EAAE,MAAM,EAAE,MAAM,UAAU,CAAA;
|
|
1
|
+
{"version":3,"file":"CheckboxGroup.js","sourceRoot":"","sources":["../../src/components/CheckboxGroup.tsx"],"names":[],"mappings":";AAAA,OAAO,EAAE,KAAK,EAAE,MAAM,QAAQ,CAAA;AAC9B,OAAO,EAAE,OAAO,EAAE,MAAM,OAAO,CAAA;AAE/B,OAAO,EAAE,gBAAgB,EAAE,kBAAkB,EAAE,MAAM,kBAAkB,CAAA;AACvE,OAAO,EAAE,OAAO,EAAE,MAAM,gBAAgB,CAAA;AACxC,OAAO,EAAE,eAAe,EAAE,MAAM,mBAAmB,CAAA;AACnD,OAAO,EAAE,MAAM,EAAE,MAAM,UAAU,CAAA;AAgFjC;;;;;;;;;;;;;;;;;;;;;;GAsBG;AACH,MAAM,CAAC,MAAM,aAAa,GAAG,OAAO,CAClC,SAAS,aAAa,CAAI,EACxB,UAAU,GAAG,UAAU,EACvB,IAAI,EACJ,KAAK,GAAG,EAAE,EACV,OAAO,EACP,QAAQ,EACR,WAAW,GAAG,kBAAkB,EAChC,SAAS,GAAG,gBAAgB,EAC5B,UAAU,EACV,UAAU,EACV,WAAW,EACX,KAAK,EACL,GAAG,GAAG,KAAK,EACX,SAAS,GAAG,IAAI,EAChB,GAAG,KAAK,EACc;IACtB,MAAM,KAAK,GAAG,OAAO,CAAC,GAAG,EAAE;QACzB,MAAM,SAAS,GAAG,KAAK,CAAC,GAAG,CAAC,SAAS,CAAC,CAAA;QACtC,OAAO,OAAO,CAAC,GAAG,CAAC,CAAC,CAAC,EAAE,EAAE;YACvB,MAAM,GAAG,GAAG,SAAS,CAAC,CAAC,CAAC,CAAA;YACxB,MAAM,QAAQ,GAAG,KAAC,eAAe,IAC/B,GAAG,EAAC,OAAO,EACX,SAAS,EAAE,UAAU,EACrB,IAAI,EAAC,UAAU,EACf,IAAI,EAAE,IAAI,EACV,KAAK,EAAE,GAAG,EACV,OAAO,EAAE,KAAK,CAAC,QAAQ,CAAC,CAAC,CAAC,IAAI,CAAC,CAAC,KAAK,CAAC,GAAG,CAAC,IAAI,SAAS,CAAC,QAAQ,CAAC,GAAG,CAAC,CAAC,EACtE,QAAQ,EAAE,CAAC,CAAC,EAAE,EAAE,CAAC,QAAQ,EAAE,CAAC,CAAC,CAAC,MAAM,CAAC,OAAO,CAAC,CAAC,CAAC,CAAC,GAAG,CAAC,KAAK,IAAI,EAAE,CAAC,EAAE,CAAC,CAAC,CAAC,CAAC,CAAC,CAAC,KAAK,EAAE,MAAM,CAAC,IAAI,CAAC,EAAE,CAAC,IAAI,IAAI,CAAC,CAAC,IAAI,EAAE,CAAC,CAAC,EAChH,QAAQ,EAAE,UAAU,EAAE,CAAC,CAAC,CAAC,EACzB,QAAQ,EAAE,SAAS,CAAC,CAAC,CAAC,SAAS,CAAC,CAAC,CAAC,CAAC,CAAC,GACpC,CAAA;YACF,OAAO,UAAU,CAAC,CAAC,CAAC,UAAU,CAAC,QAAQ,EAAE,CAAC,CAAC,CAAC,CAAC,CAAC,CAC5C,MAAC,eAAe,IAAC,GAAG,EAAC,OAAO,EAAC,SAAS,EAAE,GAAG,UAAU,MAAM,EAAY,WAAW,EAAE,WAAW,aAC5F,QAAQ,EACR,WAAW,CAAC,CAAC,CAAC,KAFiD,GAAG,CAGnD,CACnB,CAAA;QACH,CAAC,CAAC,CAAA;IACJ,CAAC,EAAE,CAAC,OAAO,EAAE,KAAK,EAAE,IAAI,EAAE,WAAW,EAAE,UAAU,CAAC,CAAC,CAAA;IACnD,OAAO,KAAC,MAAM,OAAK,KAAK,EAAE,KAAK,EAAE,EAAE,GAAG,EAAE,GAAG,KAAK,EAAE,YAAG,KAAK,GAAU,CAAA;AACtE,CAAC,CACF,CAAA"}
|
|
@@ -1,5 +1,5 @@
|
|
|
1
1
|
import { WithColorPalette, WithColorScheme } from '../types.js';
|
|
2
|
-
export type CitricComponentName = 'alert' | 'avatar' | 'badge' | 'blockquote' | 'breadcrumb' | 'button' | 'card' | 'checkbox' | 'checkbox-row' | 'divider' | 'field-group' | 'form-group' | 'form' | 'icon-box' | 'input' | 'link' | 'pagination' | 'progress-bar' | 'progress-circular' | 'radio' | 'radio-row' | 'rating' | 'select' | 'select-box' | 'skeleton' | 'slider' | 'switch' | 'switch-row' | 'table' | 'tabs' | 'accordion' | 'favorite' | 'textarea' | 'avatar-group' | 'labeled-slider' | 'rich-select' | 'tooltip' | 'menu' | 'circle';
|
|
2
|
+
export type CitricComponentName = 'alert' | 'avatar' | 'badge' | 'blockquote' | 'breadcrumb' | 'button' | 'card' | 'checkbox' | 'checkbox-row' | 'divider' | 'field-group' | 'form-group' | 'form' | 'icon-box' | 'input' | 'link' | 'pagination' | 'progress-bar' | 'progress-circular' | 'radio' | 'radio-row' | 'rating' | 'select' | 'select-box' | 'skeleton' | 'slider' | 'switch' | 'switch-row' | 'table' | 'tabs' | 'accordion' | 'favorite' | 'textarea' | 'avatar-group' | 'labeled-slider' | 'rich-select' | 'tooltip' | 'menu' | 'circle' | 'multi-select';
|
|
3
3
|
interface BaseCitricProps extends WithColorScheme, WithColorPalette {
|
|
4
4
|
component: CitricComponentName;
|
|
5
5
|
ref?: any;
|
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"CitricComponent.d.ts","sourceRoot":"","sources":["../../src/components/CitricComponent.ts"],"names":[],"mappings":"AACA,OAAO,EAAE,gBAAgB,EAAE,eAAe,EAAE,MAAM,UAAU,CAAA;AAE5D,MAAM,MAAM,mBAAmB,GAAG,OAAO,GAAG,QAAQ,GAAG,OAAO,GAAG,YAAY,GAAG,YAAY,GAAG,QAAQ,GAAG,MAAM,GAAG,UAAU,GAC3H,cAAc,GAAG,SAAS,GAAG,aAAa,GAAG,YAAY,GAAG,MAAM,GAAG,UAAU,GAAG,OAAO,GAAG,MAAM,GAAG,YAAY,GAAG,cAAc,GAClI,mBAAmB,GAAG,OAAO,GAAG,WAAW,GAAG,QAAQ,GAAG,QAAQ,GAAG,YAAY,GAAG,UAAU,GAAG,QAAQ,GAAG,QAAQ,GAAG,YAAY,GAClI,OAAO,GAAG,MAAM,GAAG,WAAW,GAAG,UAAU,GAAG,UAAU,GAAG,cAAc,GAAG,gBAAgB,GAAG,aAAa,GAAG,SAAS,GAAG,MAAM,GACjI,QAAQ,CAAA;
|
|
1
|
+
{"version":3,"file":"CitricComponent.d.ts","sourceRoot":"","sources":["../../src/components/CitricComponent.ts"],"names":[],"mappings":"AACA,OAAO,EAAE,gBAAgB,EAAE,eAAe,EAAE,MAAM,UAAU,CAAA;AAE5D,MAAM,MAAM,mBAAmB,GAAG,OAAO,GAAG,QAAQ,GAAG,OAAO,GAAG,YAAY,GAAG,YAAY,GAAG,QAAQ,GAAG,MAAM,GAAG,UAAU,GAC3H,cAAc,GAAG,SAAS,GAAG,aAAa,GAAG,YAAY,GAAG,MAAM,GAAG,UAAU,GAAG,OAAO,GAAG,MAAM,GAAG,YAAY,GAAG,cAAc,GAClI,mBAAmB,GAAG,OAAO,GAAG,WAAW,GAAG,QAAQ,GAAG,QAAQ,GAAG,YAAY,GAAG,UAAU,GAAG,QAAQ,GAAG,QAAQ,GAAG,YAAY,GAClI,OAAO,GAAG,MAAM,GAAG,WAAW,GAAG,UAAU,GAAG,UAAU,GAAG,cAAc,GAAG,gBAAgB,GAAG,aAAa,GAAG,SAAS,GAAG,MAAM,GACjI,QAAQ,GAAG,cAAc,CAAA;AAE3B,UAAU,eAAgB,SAAQ,eAAe,EAAE,gBAAgB;IACjE,SAAS,EAAE,mBAAmB,CAAC;IAC/B,GAAG,CAAC,EAAE,GAAG,CAAC;CACX;AAED,UAAU,mBAAmB;IAC3B,CAAC,CAAC,SAAS,MAAM,GAAG,CAAC,iBAAiB,EAAE,KAAK,EAAE;QAAE,GAAG,EAAE,CAAC,CAAA;KAAE,GAAG,eAAe,GAAG,GAAG,CAAC,iBAAiB,CAAC,CAAC,CAAC,GAAG,KAAK,CAAC,SAAS,CAAC;IACzH,CAAC,CAAC,SAAS,MAAM,CAAC,MAAM,EAAE,GAAG,CAAC,EAAE,KAAK,EAAE;QAAE,MAAM,EAAE,KAAK,CAAC,EAAE,CAAC,CAAC,CAAC,CAAA;KAAE,GAAG,eAAe,GAAG,CAAC,GAAG,KAAK,CAAC,SAAS,CAAC;CACxG;AAED,wBAAgB,aAAa,CAAC,EAAE,WAAW,EAAE,YAAY,EAAE,SAAS,EAAE,GAAG,KAAK,EAAE,EAAE,eAAe,GAAG,MAAM,CAAC,MAAM,EAAE,GAAG,CAAC,uBAKtH;AAED;;;;;;;;;;;;;GAaG;AAEH,eAAO,MAAM,eAAe,EAAE,mBAK7B,CAAA"}
|
|
@@ -56,6 +56,18 @@ export interface BaseRadioGroupProps<T> extends WithColorScheme {
|
|
|
56
56
|
* @returns true if the item should be disabled, false otherwise.
|
|
57
57
|
*/
|
|
58
58
|
isDisabled?: (option: T) => boolean;
|
|
59
|
+
/**
|
|
60
|
+
* The space between options.
|
|
61
|
+
*
|
|
62
|
+
* @default "8px"
|
|
63
|
+
*/
|
|
64
|
+
gap?: string;
|
|
65
|
+
/**
|
|
66
|
+
* If set to false, the checkboxes will have tabIndex = -1.
|
|
67
|
+
*
|
|
68
|
+
* @default true
|
|
69
|
+
*/
|
|
70
|
+
focusable?: boolean;
|
|
59
71
|
}
|
|
60
72
|
export type RadioGroupProps<T> = Omit<React.JSX.IntrinsicElements['div'], 'onChange' | 'children'> & BaseRadioGroupProps<T>;
|
|
61
73
|
/**
|
|
@@ -81,5 +93,5 @@ export type RadioGroupProps<T> = Omit<React.JSX.IntrinsicElements['div'], 'onCha
|
|
|
81
93
|
* return <RadioGroup options={options} renderLabel={o => o.name} renderKey={o => o.id} value={value} setValue={setValue} />
|
|
82
94
|
* ```
|
|
83
95
|
*/
|
|
84
|
-
export declare const RadioGroup: <T>({ name, value, options, onChange, renderLabel, renderKey, renderItem, isDisabled, colorScheme, style, ...props }: RadioGroupProps<T>) => import("react/jsx-runtime").JSX.Element;
|
|
96
|
+
export declare const RadioGroup: <T>({ name, value, options, onChange, renderLabel, renderKey, renderItem, isDisabled, colorScheme, gap, focusable, style, ...props }: RadioGroupProps<T>) => import("react/jsx-runtime").JSX.Element;
|
|
85
97
|
//# sourceMappingURL=RadioGroup.d.ts.map
|
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"RadioGroup.d.ts","sourceRoot":"","sources":["../../src/components/RadioGroup.tsx"],"names":[],"mappings":"AAEA,OAAO,EAAE,eAAe,EAAE,MAAM,UAAU,CAAA;AAM1C,MAAM,WAAW,mBAAmB,CAAC,CAAC,CAAE,SAAQ,eAAe;IAC7D;;OAEG;IACH,IAAI,CAAC,EAAE,MAAM,CAAC;IACd;;OAEG;IACH,KAAK,CAAC,EAAE,CAAC,CAAC;IACV;;OAEG;IACH,OAAO,EAAE,CAAC,EAAE,CAAC;IACb;;;OAGG;IACH,QAAQ,CAAC,EAAE,CAAC,KAAK,EAAE,CAAC,KAAK,IAAI,CAAC;IAC9B;;;;;;;;;;OAUG;IACH,WAAW,CAAC,EAAE,CAAC,MAAM,EAAE,CAAC,KAAK,KAAK,CAAC,SAAS,CAAC;IAC7C;;;;;;;;;OASG;IACH,UAAU,CAAC,EAAE,CAAC,KAAK,EAAE,KAAK,CAAC,YAAY,EAAE,MAAM,EAAE,CAAC,KAAK,KAAK,CAAC,SAAS,CAAC;IACvE;;;;;;;OAOG;IACH,SAAS,CAAC,EAAE,CAAC,MAAM,EAAE,CAAC,KAAK,MAAM,GAAG,MAAM,GAAG,SAAS,CAAC;IACvD;;;;;OAKG;IACH,UAAU,CAAC,EAAE,CAAC,MAAM,EAAE,CAAC,KAAK,OAAO,CAAC;
|
|
1
|
+
{"version":3,"file":"RadioGroup.d.ts","sourceRoot":"","sources":["../../src/components/RadioGroup.tsx"],"names":[],"mappings":"AAEA,OAAO,EAAE,eAAe,EAAE,MAAM,UAAU,CAAA;AAM1C,MAAM,WAAW,mBAAmB,CAAC,CAAC,CAAE,SAAQ,eAAe;IAC7D;;OAEG;IACH,IAAI,CAAC,EAAE,MAAM,CAAC;IACd;;OAEG;IACH,KAAK,CAAC,EAAE,CAAC,CAAC;IACV;;OAEG;IACH,OAAO,EAAE,CAAC,EAAE,CAAC;IACb;;;OAGG;IACH,QAAQ,CAAC,EAAE,CAAC,KAAK,EAAE,CAAC,KAAK,IAAI,CAAC;IAC9B;;;;;;;;;;OAUG;IACH,WAAW,CAAC,EAAE,CAAC,MAAM,EAAE,CAAC,KAAK,KAAK,CAAC,SAAS,CAAC;IAC7C;;;;;;;;;OASG;IACH,UAAU,CAAC,EAAE,CAAC,KAAK,EAAE,KAAK,CAAC,YAAY,EAAE,MAAM,EAAE,CAAC,KAAK,KAAK,CAAC,SAAS,CAAC;IACvE;;;;;;;OAOG;IACH,SAAS,CAAC,EAAE,CAAC,MAAM,EAAE,CAAC,KAAK,MAAM,GAAG,MAAM,GAAG,SAAS,CAAC;IACvD;;;;;OAKG;IACH,UAAU,CAAC,EAAE,CAAC,MAAM,EAAE,CAAC,KAAK,OAAO,CAAC;IACpC;;;;OAIG;IACH,GAAG,CAAC,EAAE,MAAM,CAAC;IACb;;;;OAIG;IACH,SAAS,CAAC,EAAE,OAAO,CAAC;CACrB;AAED,MAAM,MAAM,eAAe,CAAC,CAAC,IAAI,IAAI,CAAC,KAAK,CAAC,GAAG,CAAC,iBAAiB,CAAC,KAAK,CAAC,EAAE,UAAU,GAAG,UAAU,CAAC,GAAG,mBAAmB,CAAC,CAAC,CAAC,CAAA;AAE3H;;;;;;;;;;;;;;;;;;;;;;GAsBG;AACH,eAAO,MAAM,UAAU,GACD,CAAC,oIAclB,eAAe,CAAC,CAAC,CAAC,4CA0BtB,CAAA"}
|
|
@@ -28,15 +28,15 @@ import { Column } from './layout.js';
|
|
|
28
28
|
* return <RadioGroup options={options} renderLabel={o => o.name} renderKey={o => o.id} value={value} setValue={setValue} />
|
|
29
29
|
* ```
|
|
30
30
|
*/
|
|
31
|
-
export const RadioGroup = withRef(function RadioGroup({ name, value, options, onChange, renderLabel = defaultRenderLabel, renderKey = defaultRenderKey, renderItem, isDisabled, colorScheme, style, ...props }) {
|
|
31
|
+
export const RadioGroup = withRef(function RadioGroup({ name, value, options, onChange, renderLabel = defaultRenderLabel, renderKey = defaultRenderKey, renderItem, isDisabled, colorScheme, gap = '8px', focusable = true, style, ...props }) {
|
|
32
32
|
const items = useMemo(() => {
|
|
33
33
|
const valueKey = value ? renderKey(value) : undefined;
|
|
34
34
|
return options.map((o) => {
|
|
35
35
|
const key = renderKey(o);
|
|
36
|
-
const radio = _jsx(CitricComponent, { tag: "input", component: "radio", type: "radio", name: name, value: key, checked: value === o || (!isNil(key) && valueKey === key), onChange: () => onChange?.(o), disabled: isDisabled?.(o) });
|
|
36
|
+
const radio = _jsx(CitricComponent, { tag: "input", component: "radio", type: "radio", name: name, value: key, checked: value === o || (!isNil(key) && valueKey === key), onChange: () => onChange?.(o), disabled: isDisabled?.(o), tabIndex: focusable ? undefined : -1 });
|
|
37
37
|
return renderItem ? renderItem(radio, o) : (_jsxs(CitricComponent, { tag: "label", component: "radio-row", colorScheme: colorScheme, children: [radio, renderLabel(o)] }, key));
|
|
38
38
|
});
|
|
39
39
|
}, [options, value, name, colorScheme]);
|
|
40
|
-
return _jsx(Column, { ...props, style: { gap
|
|
40
|
+
return _jsx(Column, { ...props, style: { gap, ...style }, children: items });
|
|
41
41
|
});
|
|
42
42
|
//# sourceMappingURL=RadioGroup.js.map
|
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"RadioGroup.js","sourceRoot":"","sources":["../../src/components/RadioGroup.tsx"],"names":[],"mappings":";AAAA,OAAO,EAAE,KAAK,EAAE,MAAM,QAAQ,CAAA;AAC9B,OAAO,EAAE,OAAO,EAAE,MAAM,OAAO,CAAA;AAE/B,OAAO,EAAE,gBAAgB,EAAE,kBAAkB,EAAE,MAAM,kBAAkB,CAAA;AACvE,OAAO,EAAE,OAAO,EAAE,MAAM,gBAAgB,CAAA;AACxC,OAAO,EAAE,eAAe,EAAE,MAAM,mBAAmB,CAAA;AACnD,OAAO,EAAE,MAAM,EAAE,MAAM,UAAU,CAAA;
|
|
1
|
+
{"version":3,"file":"RadioGroup.js","sourceRoot":"","sources":["../../src/components/RadioGroup.tsx"],"names":[],"mappings":";AAAA,OAAO,EAAE,KAAK,EAAE,MAAM,QAAQ,CAAA;AAC9B,OAAO,EAAE,OAAO,EAAE,MAAM,OAAO,CAAA;AAE/B,OAAO,EAAE,gBAAgB,EAAE,kBAAkB,EAAE,MAAM,kBAAkB,CAAA;AACvE,OAAO,EAAE,OAAO,EAAE,MAAM,gBAAgB,CAAA;AACxC,OAAO,EAAE,eAAe,EAAE,MAAM,mBAAmB,CAAA;AACnD,OAAO,EAAE,MAAM,EAAE,MAAM,UAAU,CAAA;AA2EjC;;;;;;;;;;;;;;;;;;;;;;GAsBG;AACH,MAAM,CAAC,MAAM,UAAU,GAAG,OAAO,CAC/B,SAAS,UAAU,CAAI,EACrB,IAAI,EACJ,KAAK,EACL,OAAO,EACP,QAAQ,EACR,WAAW,GAAG,kBAAkB,EAChC,SAAS,GAAG,gBAAgB,EAC5B,UAAU,EACV,UAAU,EACV,WAAW,EACX,GAAG,GAAG,KAAK,EACX,SAAS,GAAG,IAAI,EAChB,KAAK,EACL,GAAG,KAAK,EACW;IACnB,MAAM,KAAK,GAAG,OAAO,CAAC,GAAG,EAAE;QACzB,MAAM,QAAQ,GAAG,KAAK,CAAC,CAAC,CAAC,SAAS,CAAC,KAAK,CAAC,CAAC,CAAC,CAAC,SAAS,CAAA;QACrD,OAAO,OAAO,CAAC,GAAG,CAAC,CAAC,CAAC,EAAE,EAAE;YACvB,MAAM,GAAG,GAAG,SAAS,CAAC,CAAC,CAAC,CAAA;YACxB,MAAM,KAAK,GAAG,KAAC,eAAe,IAC5B,GAAG,EAAC,OAAO,EACX,SAAS,EAAC,OAAO,EACjB,IAAI,EAAC,OAAO,EACZ,IAAI,EAAE,IAAI,EACV,KAAK,EAAE,GAAG,EACV,OAAO,EAAE,KAAK,KAAK,CAAC,IAAI,CAAC,CAAC,KAAK,CAAC,GAAG,CAAC,IAAI,QAAQ,KAAK,GAAG,CAAC,EACzD,QAAQ,EAAE,GAAG,EAAE,CAAC,QAAQ,EAAE,CAAC,CAAC,CAAC,EAC7B,QAAQ,EAAE,UAAU,EAAE,CAAC,CAAC,CAAC,EACzB,QAAQ,EAAE,SAAS,CAAC,CAAC,CAAC,SAAS,CAAC,CAAC,CAAC,CAAC,CAAC,GACpC,CAAA;YACF,OAAO,UAAU,CAAC,CAAC,CAAC,UAAU,CAAC,KAAK,EAAE,CAAC,CAAC,CAAC,CAAC,CAAC,CACzC,MAAC,eAAe,IAAC,GAAG,EAAC,OAAO,EAAC,SAAS,EAAC,WAAW,EAAW,WAAW,EAAE,WAAW,aAClF,KAAK,EACL,WAAW,CAAC,CAAC,CAAC,KAFuC,GAAG,CAGzC,CACnB,CAAA;QACH,CAAC,CAAC,CAAA;IACJ,CAAC,EAAE,CAAC,OAAO,EAAE,KAAK,EAAE,IAAI,EAAE,WAAW,CAAC,CAAC,CAAA;IACvC,OAAO,KAAC,MAAM,OAAK,KAAK,EAAE,KAAK,EAAE,EAAE,GAAG,EAAE,GAAG,KAAK,EAAE,YAAG,KAAK,GAAU,CAAA;AACtE,CAAC,CACF,CAAA"}
|
|
@@ -0,0 +1,60 @@
|
|
|
1
|
+
import { RichSelectProps } from './types.js';
|
|
2
|
+
export interface BaseMultiSelectProps<T> extends Omit<RichSelectProps<T>, 'value' | 'onChange' | 'renderHeader' | 'renderLabel' | 'renderOption' | 'required' | 'onFocus' | 'onBlur'> {
|
|
3
|
+
value: T[];
|
|
4
|
+
onChange: (value: T[]) => void;
|
|
5
|
+
/**
|
|
6
|
+
* A function to render the option in the selectable list.
|
|
7
|
+
*
|
|
8
|
+
* The `renderLabel` function is used if this is not provided.
|
|
9
|
+
* @param value the option.
|
|
10
|
+
* @returns the React Node.
|
|
11
|
+
*/
|
|
12
|
+
renderOption?: (option: T) => React.ReactNode;
|
|
13
|
+
/**
|
|
14
|
+
* A function to render the selected options in the header.
|
|
15
|
+
*
|
|
16
|
+
* The `renderOption` function is used if this is not provided.
|
|
17
|
+
* @param value the option.
|
|
18
|
+
* @returns the React Node.
|
|
19
|
+
*/
|
|
20
|
+
renderHeader?: (value: T[]) => React.ReactNode;
|
|
21
|
+
/**
|
|
22
|
+
* A function to render the item label.
|
|
23
|
+
* @example
|
|
24
|
+
* `(option) => option.name`
|
|
25
|
+
* @default "the item's toString() result."
|
|
26
|
+
* @param option the item to render.
|
|
27
|
+
* @returns a React Node to render.
|
|
28
|
+
*/
|
|
29
|
+
renderLabel?: (option: T) => string;
|
|
30
|
+
/**
|
|
31
|
+
* Whether or not to show a checkbox to select all or remove the selection.
|
|
32
|
+
*
|
|
33
|
+
* @default false
|
|
34
|
+
*/
|
|
35
|
+
showSelectAll?: boolean;
|
|
36
|
+
}
|
|
37
|
+
export type MultiSelectProps<T> = Omit<React.JSX.IntrinsicElements['div'], 'ref' | 'onChange' | 'onFocus' | 'onBlur'> & BaseMultiSelectProps<T>;
|
|
38
|
+
/**
|
|
39
|
+
* A component that looks like a Select and behaves like a CheckboxGroup. This is a component that lets the user select multiple options
|
|
40
|
+
* in a list.
|
|
41
|
+
*
|
|
42
|
+
* Differently than then the component Select, this does not render the native select of the browser. Instead, it renders a series of
|
|
43
|
+
* checkboxes.
|
|
44
|
+
*
|
|
45
|
+
* @example
|
|
46
|
+
*
|
|
47
|
+
* ```
|
|
48
|
+
* const options = useMemo(() => [
|
|
49
|
+
* { id: 1, name: 'Option 1' },
|
|
50
|
+
* { id: 2, name: 'Option 2' },
|
|
51
|
+
* { id: 3, name: 'Option 3' },
|
|
52
|
+
* ], [])
|
|
53
|
+
*
|
|
54
|
+
* const [value, setValue] = useState<typeof options>([])
|
|
55
|
+
*
|
|
56
|
+
* return <MultiSelect options={options} renderLabel={o => o.name} renderKey={o => o.id} value={value} setValue={setValue} />
|
|
57
|
+
* ```
|
|
58
|
+
*/
|
|
59
|
+
export declare const MultiSelect: <T>({ ref, options, value, onChange, renderLabel, renderKey, disabled, loading, renderOption, renderHeader, searchable, maxHeight, style, className, showArrow, placeholder, showSelectAll, ...props }: MultiSelectProps<T>) => import("react/jsx-runtime").JSX.Element;
|
|
60
|
+
//# sourceMappingURL=MultiSelect.d.ts.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"MultiSelect.d.ts","sourceRoot":"","sources":["../../../src/components/Select/MultiSelect.tsx"],"names":[],"mappings":"AAcA,OAAO,EAAE,eAAe,EAAE,MAAM,SAAS,CAAA;AAEzC,MAAM,WAAW,oBAAoB,CAAC,CAAC,CAAE,SACvC,IAAI,CAAC,eAAe,CAAC,CAAC,CAAC,EAAE,OAAO,GAAG,UAAU,GAAG,cAAc,GAAG,aAAa,GAAG,cAAc,GAAG,UAAU,GAAG,SAAS,GAAG,QAAQ,CAAC;IACpI,KAAK,EAAE,CAAC,EAAE,CAAC;IACX,QAAQ,EAAE,CAAC,KAAK,EAAE,CAAC,EAAE,KAAK,IAAI,CAAC;IAC/B;;;;;;OAMG;IACH,YAAY,CAAC,EAAE,CAAC,MAAM,EAAE,CAAC,KAAK,KAAK,CAAC,SAAS,CAAC;IAC9C;;;;;;OAMG;IACH,YAAY,CAAC,EAAE,CAAC,KAAK,EAAE,CAAC,EAAE,KAAK,KAAK,CAAC,SAAS,CAAC;IAC/C;;;;;;;OAOG;IACH,WAAW,CAAC,EAAE,CAAC,MAAM,EAAE,CAAC,KAAK,MAAM,CAAC;IACpC;;;;OAIG;IACH,aAAa,CAAC,EAAE,OAAO,CAAC;CACzB;AAED,MAAM,MAAM,gBAAgB,CAAC,CAAC,IAAI,IAAI,CAAC,KAAK,CAAC,GAAG,CAAC,iBAAiB,CAAC,KAAK,CAAC,EAAE,KAAK,GAAG,UAAU,GAAG,SAAS,GAAG,QAAQ,CAAC,GACnH,oBAAoB,CAAC,CAAC,CAAC,CAAA;AAEzB;;;;;;;;;;;;;;;;;;;;GAoBG;AACH,eAAO,MAAM,WAAW,GACD,CAAC,sMAmBnB,gBAAgB,CAAC,CAAC,CAAC,4CA4FvB,CAAA"}
|
|
@@ -0,0 +1,84 @@
|
|
|
1
|
+
import { jsx as _jsx, jsxs as _jsxs } from "react/jsx-runtime";
|
|
2
|
+
import { listToClass } from '@stack-spot/portal-theme';
|
|
3
|
+
import { useTranslate } from '@stack-spot/portal-translate';
|
|
4
|
+
import { useMemo, useRef, useState } from 'react';
|
|
5
|
+
import { useCheckboxGroupControls } from '../../utils/checkbox.js';
|
|
6
|
+
import { applyCSSVariable } from '../../utils/css.js';
|
|
7
|
+
import { defaultRenderKey, defaultRenderLabel } from '../../utils/options.js';
|
|
8
|
+
import { withRef } from '../../utils/react.js';
|
|
9
|
+
import { Checkbox } from '../Checkbox.js';
|
|
10
|
+
import { CheckboxGroup } from '../CheckboxGroup.js';
|
|
11
|
+
import { CitricComponent } from '../CitricComponent.js';
|
|
12
|
+
import { Input } from '../Input.js';
|
|
13
|
+
import { Row } from '../layout.js';
|
|
14
|
+
import { ProgressCircular } from '../ProgressCircular.js';
|
|
15
|
+
import { useDisabledEffect, useFocusEffect, useOpenPanelEffect } from './hooks.js';
|
|
16
|
+
/**
|
|
17
|
+
* A component that looks like a Select and behaves like a CheckboxGroup. This is a component that lets the user select multiple options
|
|
18
|
+
* in a list.
|
|
19
|
+
*
|
|
20
|
+
* Differently than then the component Select, this does not render the native select of the browser. Instead, it renders a series of
|
|
21
|
+
* checkboxes.
|
|
22
|
+
*
|
|
23
|
+
* @example
|
|
24
|
+
*
|
|
25
|
+
* ```
|
|
26
|
+
* const options = useMemo(() => [
|
|
27
|
+
* { id: 1, name: 'Option 1' },
|
|
28
|
+
* { id: 2, name: 'Option 2' },
|
|
29
|
+
* { id: 3, name: 'Option 3' },
|
|
30
|
+
* ], [])
|
|
31
|
+
*
|
|
32
|
+
* const [value, setValue] = useState<typeof options>([])
|
|
33
|
+
*
|
|
34
|
+
* return <MultiSelect options={options} renderLabel={o => o.name} renderKey={o => o.id} value={value} setValue={setValue} />
|
|
35
|
+
* ```
|
|
36
|
+
*/
|
|
37
|
+
export const MultiSelect = withRef(function MultiSelect({ ref, options, value = [], onChange, renderLabel = defaultRenderLabel, renderKey = defaultRenderKey, disabled, loading, renderOption, renderHeader, searchable, maxHeight, style, className, showArrow, placeholder, showSelectAll, ...props }) {
|
|
38
|
+
const t = useTranslate(dictionary);
|
|
39
|
+
const _element = useRef(null);
|
|
40
|
+
const element = ref ?? _element;
|
|
41
|
+
const [open, setOpen] = useState(false);
|
|
42
|
+
const [focused, setFocused] = useState(false);
|
|
43
|
+
const controls = useCheckboxGroupControls({
|
|
44
|
+
options,
|
|
45
|
+
renderKey,
|
|
46
|
+
initialValue: value,
|
|
47
|
+
onChange,
|
|
48
|
+
applyFilter: (filter, option) => renderLabel(option).toLocaleLowerCase().includes(filter.toLocaleLowerCase()),
|
|
49
|
+
});
|
|
50
|
+
useOpenPanelEffect({ open, setOpen, setSearch: controls.setFilter, element, searchable });
|
|
51
|
+
useFocusEffect({ element, focused, setFocused, setOpen });
|
|
52
|
+
useDisabledEffect({ disabled, setOpen, setFocused });
|
|
53
|
+
const header = useMemo(() => {
|
|
54
|
+
if (value.length === 0)
|
|
55
|
+
return _jsx("span", { className: "placeholder", children: placeholder });
|
|
56
|
+
const reverse = value.reverse();
|
|
57
|
+
return ((renderHeader?.(reverse)
|
|
58
|
+
?? (renderOption ? _jsx(Row, { gap: "4px", children: reverse.map(renderOption) }) : _jsx("span", { children: reverse.map(renderLabel).join(', ') })))
|
|
59
|
+
|| _jsx("span", {}));
|
|
60
|
+
}, [value, placeholder]);
|
|
61
|
+
return (_jsxs(CitricComponent, { tag: "div", component: "multi-select", style: maxHeight ? applyCSSVariable(style, 'max-height', `${maxHeight}px`) : style, className: listToClass([className, showArrow === false && 'hide-arrow', open && 'open', focused && 'focused']), ref: element, "aria-busy": loading, ...props, children: [_jsxs("header", { onClick: (e) => {
|
|
62
|
+
if (disabled)
|
|
63
|
+
return;
|
|
64
|
+
if (!open)
|
|
65
|
+
e.stopPropagation();
|
|
66
|
+
setFocused(true);
|
|
67
|
+
setOpen(true);
|
|
68
|
+
}, onFocus: () => setFocused(true), "aria-label": t.accessibilityHelp, tabIndex: 0, className: renderHeader ? 'custom' : undefined, children: [header, loading && _jsx(ProgressCircular, { size: "xs", className: "loader" })] }), _jsxs("div", { className: "selection-panel", "aria-hidden": !open, ...(open ? {} : { inert: 'true' }), children: [searchable && _jsx("div", { className: "search-bar", children: _jsxs("div", { "data-citric": "field-group", className: "auto", children: [_jsx("i", { "data-citric": "icon-box", className: "citric-icon outline Search" }), _jsx(Input, { type: "search", value: controls.filter, onChange: controls.setFilter, "aria-label": t.searchAccessibility })] }) }), showSelectAll && (_jsx(Checkbox, { className: "select-all", onChange: checked => checked ? controls.selectAll() : controls.removeSelection(), value: controls.isAllSelected, children: controls.isAllSelected ? t.removeSelection : t.selectAll })), _jsx(CheckboxGroup, { className: "options", gap: "0", options: controls.options, onChange: controls.setValue, value: controls.value, renderKey: controls.renderKey, focusable: false, renderItem: (checkbox, option) => (_jsxs(CitricComponent, { component: "checkbox-row", tag: "label", className: listToClass(['option', controls.isUnfilteredButChecked(option) && 'unfiltered']), children: [checkbox, renderOption?.(option) ?? renderLabel(option)] })) })] })] }));
|
|
69
|
+
});
|
|
70
|
+
const dictionary = {
|
|
71
|
+
en: {
|
|
72
|
+
accessibilityHelp: 'Press the arrow down to select multiple options',
|
|
73
|
+
searchAccessibility: 'Filter the options',
|
|
74
|
+
removeSelection: 'Remove selection',
|
|
75
|
+
selectAll: 'Select all',
|
|
76
|
+
},
|
|
77
|
+
pt: {
|
|
78
|
+
accessibilityHelp: 'Pressione a seta para baixo para selecionar múltiplas opções',
|
|
79
|
+
searchAccessibility: 'Filtre as opções',
|
|
80
|
+
removeSelection: 'Remover seleção',
|
|
81
|
+
selectAll: 'Selecionar todos',
|
|
82
|
+
},
|
|
83
|
+
};
|
|
84
|
+
//# sourceMappingURL=MultiSelect.js.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"MultiSelect.js","sourceRoot":"","sources":["../../../src/components/Select/MultiSelect.tsx"],"names":[],"mappings":"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"}
|
|
@@ -1,5 +1,5 @@
|
|
|
1
1
|
import { SelectProps } from './types.js';
|
|
2
|
-
export declare const RichSelect: <T>({ ref, options, value, onChange, renderLabel, renderKey, required, disabled, loading, renderOption, renderHeader, searchable, maxHeight, style, className, onFocus, onBlur, showArrow, ...props }: SelectProps<T> & {
|
|
2
|
+
export declare const RichSelect: <T>({ ref, options, value, onChange, renderLabel, renderKey, required, disabled, loading, renderOption, renderHeader, searchable, maxHeight, style, className, onFocus, onBlur, showArrow, placeholder, ...props }: SelectProps<T> & {
|
|
3
3
|
type?: "rich";
|
|
4
4
|
}) => import("react/jsx-runtime").JSX.Element;
|
|
5
5
|
//# sourceMappingURL=RichSelect.d.ts.map
|
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"RichSelect.d.ts","sourceRoot":"","sources":["../../../src/components/Select/RichSelect.tsx"],"names":[],"mappings":"
|
|
1
|
+
{"version":3,"file":"RichSelect.d.ts","sourceRoot":"","sources":["../../../src/components/Select/RichSelect.tsx"],"names":[],"mappings":"AAWA,OAAO,EAAE,WAAW,EAAE,MAAM,SAAS,CAAA;AAErC,eAAO,MAAM,UAAU,GACD,CAAC,kNAqBlB,WAAW,CAAC,CAAC,CAAC,GAAG;IAAE,IAAI,CAAC,EAAE,MAAM,CAAA;CAAE,4CAoFtC,CAAA"}
|
|
@@ -1,15 +1,16 @@
|
|
|
1
1
|
import { jsx as _jsx, jsxs as _jsxs } from "react/jsx-runtime";
|
|
2
2
|
import { listToClass } from '@stack-spot/portal-theme';
|
|
3
3
|
import { useTranslate } from '@stack-spot/portal-translate';
|
|
4
|
-
import { useCallback,
|
|
4
|
+
import { useCallback, useMemo, useRef, useState } from 'react';
|
|
5
5
|
import { applyCSSVariable } from '../../utils/css.js';
|
|
6
6
|
import { defaultRenderKey, defaultRenderLabel } from '../../utils/options.js';
|
|
7
7
|
import { withRef } from '../../utils/react.js';
|
|
8
8
|
import { CitricComponent } from '../CitricComponent.js';
|
|
9
9
|
import { Input } from '../Input.js';
|
|
10
10
|
import { ProgressCircular } from '../ProgressCircular.js';
|
|
11
|
+
import { useDisabledEffect, useFocusEffect, useOpenPanelEffect } from './hooks.js';
|
|
11
12
|
import { SimpleSelect } from './SimpleSelect.js';
|
|
12
|
-
export const RichSelect = withRef(function RichSelect({ ref, options, value, onChange, renderLabel = defaultRenderLabel, renderKey = defaultRenderKey, required = true, disabled, loading, renderOption, renderHeader, searchable, maxHeight, style, className, onFocus, onBlur, showArrow, ...props }) {
|
|
13
|
+
export const RichSelect = withRef(function RichSelect({ ref, options, value, onChange, renderLabel = defaultRenderLabel, renderKey = defaultRenderKey, required = true, disabled, loading, renderOption, renderHeader, searchable, maxHeight, style, className, onFocus, onBlur, showArrow, placeholder, ...props }) {
|
|
13
14
|
const [search, setSearch] = useState('');
|
|
14
15
|
const _element = useRef(null);
|
|
15
16
|
const element = ref ?? _element;
|
|
@@ -21,122 +22,21 @@ export const RichSelect = withRef(function RichSelect({ ref, options, value, onC
|
|
|
21
22
|
setOpen(false);
|
|
22
23
|
}, []);
|
|
23
24
|
const renderedOptions = useMemo(() => {
|
|
24
|
-
const items = required
|
|
25
|
+
const items = required
|
|
26
|
+
? []
|
|
27
|
+
: [_jsx("li", { className: "empty option", onClick: change(undefined), children: renderLabel(undefined) || t.empty }, "")];
|
|
25
28
|
options.forEach((o) => {
|
|
26
29
|
const key = renderKey(o);
|
|
27
30
|
const label = renderLabel(o);
|
|
28
|
-
if (!search
|
|
29
|
-
items.push(_jsx("li", { onClick: change(o), children: renderOption?.(o) ?? label }, key));
|
|
31
|
+
if (!search?.trim() || label.toLocaleLowerCase().includes(search?.trim().toLocaleLowerCase())) {
|
|
32
|
+
items.push(_jsx("li", { onClick: change(o), className: "option", children: renderOption?.(o) ?? label }, key));
|
|
30
33
|
}
|
|
31
34
|
});
|
|
32
35
|
return items;
|
|
33
36
|
}, [options, value, required, search]);
|
|
34
|
-
|
|
35
|
-
|
|
36
|
-
|
|
37
|
-
setSearch('');
|
|
38
|
-
const selectionPanel = element.current?.querySelector('.selection-panel');
|
|
39
|
-
selectionPanel?.querySelector('ul')?.scrollTo({ top: 0 });
|
|
40
|
-
const getCurrent = () => selectionPanel?.querySelector('li.focused');
|
|
41
|
-
const scrollTo = (li) => {
|
|
42
|
-
const ul = li.closest('ul');
|
|
43
|
-
if (!ul)
|
|
44
|
-
return;
|
|
45
|
-
const { top: ulTop, height: ulHeight } = ul.getBoundingClientRect();
|
|
46
|
-
const { height: liHeight, top: liTop } = li.getBoundingClientRect();
|
|
47
|
-
const offset = liTop + ul.scrollTop - ulTop;
|
|
48
|
-
if ((ul.scrollTop + ulHeight < offset + liHeight) || ul.scrollTop > offset) {
|
|
49
|
-
ul.scrollTo({ top: offset });
|
|
50
|
-
}
|
|
51
|
-
};
|
|
52
|
-
/* keyboard and mouse controls */
|
|
53
|
-
const listenToMouse = (event) => {
|
|
54
|
-
if (!selectionPanel?.contains(event.target)) {
|
|
55
|
-
setOpen(false);
|
|
56
|
-
}
|
|
57
|
-
};
|
|
58
|
-
const listenToKeyboard = (event) => {
|
|
59
|
-
const isCharacter = event.key.length === 1;
|
|
60
|
-
if (['Escape', 'ArrowUp', 'ArrowDown', 'Enter'].includes(event.key) ||
|
|
61
|
-
(searchable && (isCharacter || event.key === 'Backspace'))) {
|
|
62
|
-
event.preventDefault();
|
|
63
|
-
event.stopPropagation();
|
|
64
|
-
}
|
|
65
|
-
if (event.key === 'Escape')
|
|
66
|
-
setOpen(false);
|
|
67
|
-
if (searchable) {
|
|
68
|
-
if (isCharacter)
|
|
69
|
-
setSearch(v => `${v}${event.key}`);
|
|
70
|
-
if (event.key === 'Backspace')
|
|
71
|
-
setSearch(v => v.substring(0, v.length - 1));
|
|
72
|
-
}
|
|
73
|
-
if (event.key === 'ArrowDown') {
|
|
74
|
-
const current = getCurrent();
|
|
75
|
-
const next = (current?.nextElementSibling ?? selectionPanel?.querySelector('li'));
|
|
76
|
-
if (next) {
|
|
77
|
-
current?.classList.remove('focused');
|
|
78
|
-
next.classList.add('focused');
|
|
79
|
-
scrollTo(next);
|
|
80
|
-
}
|
|
81
|
-
}
|
|
82
|
-
if (event.key === 'ArrowUp') {
|
|
83
|
-
const current = getCurrent();
|
|
84
|
-
const prev = (current?.previousElementSibling ?? selectionPanel?.querySelector('li:last-child'));
|
|
85
|
-
if (prev) {
|
|
86
|
-
current?.classList.remove('focused');
|
|
87
|
-
prev.classList.add('focused');
|
|
88
|
-
scrollTo(prev);
|
|
89
|
-
}
|
|
90
|
-
}
|
|
91
|
-
if (event.key === 'Enter') {
|
|
92
|
-
setTimeout(() => getCurrent()?.click(), 0);
|
|
93
|
-
}
|
|
94
|
-
};
|
|
95
|
-
// below, we wait 20ms so the same click that opened the select doesn't close it. Removing it will cause problems with selects under
|
|
96
|
-
// labels.
|
|
97
|
-
setTimeout(() => document.addEventListener('click', listenToMouse), 20);
|
|
98
|
-
document.addEventListener('keydown', listenToKeyboard);
|
|
99
|
-
return () => {
|
|
100
|
-
document.removeEventListener('click', listenToMouse);
|
|
101
|
-
document.removeEventListener('keydown', listenToKeyboard);
|
|
102
|
-
getCurrent()?.classList.remove('focused');
|
|
103
|
-
};
|
|
104
|
-
}
|
|
105
|
-
}, [open]);
|
|
106
|
-
/* this runs whenever the select is focused */
|
|
107
|
-
useEffect(() => {
|
|
108
|
-
if (focused) {
|
|
109
|
-
const listenToMouse = (event) => {
|
|
110
|
-
if (!element.current?.contains(event.target)) {
|
|
111
|
-
setFocused(false);
|
|
112
|
-
}
|
|
113
|
-
};
|
|
114
|
-
const listenToKeyboard = (event) => {
|
|
115
|
-
if (['Enter', 'ArrowDown', 'ArrowUp'].includes(event.key)) {
|
|
116
|
-
event.preventDefault();
|
|
117
|
-
if (!element.current?.classList.contains('open'))
|
|
118
|
-
setOpen(true);
|
|
119
|
-
}
|
|
120
|
-
if (event.key === 'Tab') {
|
|
121
|
-
setFocused(false);
|
|
122
|
-
if (element.current?.classList.contains('open'))
|
|
123
|
-
setOpen(false);
|
|
124
|
-
}
|
|
125
|
-
};
|
|
126
|
-
document.addEventListener('click', listenToMouse);
|
|
127
|
-
document.addEventListener('keydown', listenToKeyboard);
|
|
128
|
-
return () => {
|
|
129
|
-
document.removeEventListener('click', listenToMouse);
|
|
130
|
-
document.removeEventListener('keydown', listenToKeyboard);
|
|
131
|
-
};
|
|
132
|
-
}
|
|
133
|
-
}, [focused]);
|
|
134
|
-
useEffect(() => {
|
|
135
|
-
if (disabled) {
|
|
136
|
-
setOpen(false);
|
|
137
|
-
setFocused(false);
|
|
138
|
-
}
|
|
139
|
-
}, [disabled]);
|
|
37
|
+
useOpenPanelEffect({ open, setOpen, setSearch, element, searchable });
|
|
38
|
+
useFocusEffect({ element, focused, setFocused, setOpen });
|
|
39
|
+
useDisabledEffect({ disabled, setOpen, setFocused });
|
|
140
40
|
return (_jsxs(CitricComponent, { tag: "div", component: "rich-select", style: maxHeight ? applyCSSVariable(style, 'max-height', `${maxHeight}px`) : style, className: listToClass([className, showArrow === false && 'hide-arrow', open && 'open', focused && 'focused']), ref: element, "aria-busy": loading, ...props, children: [_jsx(SimpleSelect, { options: options, value: value, renderLabel: renderLabel, renderKey: renderKey, required: required, disabled: disabled, onChange: onChange, onFocus: onFocus, onBlur: onBlur, wrap: false }), _jsxs("header", { onClick: (e) => {
|
|
141
41
|
if (disabled)
|
|
142
42
|
return;
|
|
@@ -144,7 +44,9 @@ export const RichSelect = withRef(function RichSelect({ ref, options, value, onC
|
|
|
144
44
|
e.stopPropagation();
|
|
145
45
|
setFocused(true);
|
|
146
46
|
setOpen(true);
|
|
147
|
-
}, "aria-hidden": true, children: [
|
|
47
|
+
}, "aria-hidden": true, children: [value === undefined
|
|
48
|
+
? _jsx("span", { className: "placeholder", children: placeholder })
|
|
49
|
+
: ((renderHeader?.(value) ?? renderOption?.(value) ?? renderLabel(value)) || _jsx("span", {})), loading && _jsx(ProgressCircular, { size: "xs", className: "loader" })] }), _jsxs("div", { className: "selection-panel", "aria-hidden": true, children: [searchable && _jsx("div", { className: "search-bar", children: _jsxs("div", { "data-citric": "field-group", className: "auto", children: [_jsx("i", { "data-citric": "icon-box", className: "citric-icon outline Search" }), _jsx(Input, { type: "search", value: search, onChange: setSearch, tabIndex: -1 })] }) }), _jsx("ul", { className: "options", children: renderedOptions })] })] }));
|
|
148
50
|
});
|
|
149
51
|
const dictionary = {
|
|
150
52
|
en: {
|