@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.
Files changed (41) hide show
  1. package/dist/citric.css +54 -3
  2. package/dist/components/CheckboxGroup.d.ts +15 -1
  3. package/dist/components/CheckboxGroup.d.ts.map +1 -1
  4. package/dist/components/CheckboxGroup.js +5 -3
  5. package/dist/components/CheckboxGroup.js.map +1 -1
  6. package/dist/components/CitricComponent.d.ts +1 -1
  7. package/dist/components/CitricComponent.d.ts.map +1 -1
  8. package/dist/components/RadioGroup.d.ts +13 -1
  9. package/dist/components/RadioGroup.d.ts.map +1 -1
  10. package/dist/components/RadioGroup.js +3 -3
  11. package/dist/components/RadioGroup.js.map +1 -1
  12. package/dist/components/Select/MultiSelect.d.ts +60 -0
  13. package/dist/components/Select/MultiSelect.d.ts.map +1 -0
  14. package/dist/components/Select/MultiSelect.js +84 -0
  15. package/dist/components/Select/MultiSelect.js.map +1 -0
  16. package/dist/components/Select/RichSelect.d.ts +1 -1
  17. package/dist/components/Select/RichSelect.d.ts.map +1 -1
  18. package/dist/components/Select/RichSelect.js +14 -112
  19. package/dist/components/Select/RichSelect.js.map +1 -1
  20. package/dist/components/Select/hooks.d.ts +23 -0
  21. package/dist/components/Select/hooks.d.ts.map +1 -0
  22. package/dist/components/Select/hooks.js +114 -0
  23. package/dist/components/Select/hooks.js.map +1 -0
  24. package/dist/components/Select/types.d.ts +16 -5
  25. package/dist/components/Select/types.d.ts.map +1 -1
  26. package/dist/index.d.ts +1 -0
  27. package/dist/index.d.ts.map +1 -1
  28. package/dist/index.js +1 -0
  29. package/dist/index.js.map +1 -1
  30. package/dist/utils/checkbox.js +1 -1
  31. package/dist/utils/checkbox.js.map +1 -1
  32. package/package.json +1 -1
  33. package/src/components/CheckboxGroup.tsx +18 -1
  34. package/src/components/CitricComponent.ts +1 -1
  35. package/src/components/RadioGroup.tsx +16 -1
  36. package/src/components/Select/MultiSelect.tsx +205 -0
  37. package/src/components/Select/RichSelect.tsx +16 -109
  38. package/src/components/Select/hooks.ts +133 -0
  39. package/src/components/Select/types.ts +16 -5
  40. package/src/index.ts +1 -0
  41. 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
- ul {
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
- li {
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;CACrC;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;;;;;;;;;;;;;;;;;;;;GAoBG;AACH,eAAO,MAAM,aAAa,GACD,CAAC,gIAarB,kBAAkB,CAAC,CAAC,CAAC,4CAyBzB,CAAA"}
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: '8px', ...style }, children: items });
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;AAoEjC;;;;;;;;;;;;;;;;;;;;GAoBG;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,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,GACzB,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,KAAK,EAAE,GAAG,KAAK,EAAE,YAAG,KAAK,GAAU,CAAA;AAC7E,CAAC,CACF,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;AAEV,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"}
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;CACrC;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,oHAYlB,eAAe,CAAC,CAAC,CAAC,4CAyBtB,CAAA"}
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: '8px', ...style }, children: items });
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;AA+DjC;;;;;;;;;;;;;;;;;;;;;;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,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,GACzB,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,KAAK,EAAE,GAAG,KAAK,EAAE,YAAG,KAAK,GAAU,CAAA;AAC7E,CAAC,CACF,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":"AAUA,OAAO,EAAE,WAAW,EAAE,MAAM,SAAS,CAAA;AAErC,eAAO,MAAM,UAAU,GACD,CAAC,qMAoBlB,WAAW,CAAC,CAAC,CAAC,GAAG;IAAE,IAAI,CAAC,EAAE,MAAM,CAAA;CAAE,4CAmLtC,CAAA"}
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, useEffect, useMemo, useRef, useState } from 'react';
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 ? [] : [_jsx("li", { className: "empty", onClick: change(undefined), children: renderLabel(undefined) || t.empty }, "")];
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.trim() || label.toLocaleLowerCase().includes(search.trim().toLocaleLowerCase())) {
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
- /* this runs whenever the selection panel is opened */
35
- useEffect(() => {
36
- if (open) {
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: [(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", { children: renderedOptions })] })] }));
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: {