@panneau/ui 5.0.0-alpha.4 → 5.0.0-alpha.6

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 (121) hide show
  1. package/README.md +55 -2
  2. package/dist/command-palette/CommandPalette.css +299 -0
  3. package/dist/command-palette/CommandPalette.d.ts +37 -0
  4. package/dist/command-palette/CommandPalette.d.ts.map +1 -0
  5. package/dist/command-palette/CommandPalette.js +194 -0
  6. package/dist/command-palette/CommandPalette.js.map +1 -0
  7. package/dist/command-palette/CommandPalette.module.js +62 -0
  8. package/dist/command-palette/CommandPalette.module.js.map +1 -0
  9. package/dist/command-palette/match.d.ts +39 -0
  10. package/dist/command-palette/match.d.ts.map +1 -0
  11. package/dist/command-palette/match.js +44 -0
  12. package/dist/command-palette/match.js.map +1 -0
  13. package/dist/command-palette/tokens.d.ts +3 -0
  14. package/dist/command-palette/tokens.d.ts.map +1 -0
  15. package/dist/command-palette/tokens.js +23 -0
  16. package/dist/command-palette/tokens.js.map +1 -0
  17. package/dist/command-palette/useCommandShortcut.d.ts +12 -0
  18. package/dist/command-palette/useCommandShortcut.d.ts.map +1 -0
  19. package/dist/command-palette/useCommandShortcut.js +29 -0
  20. package/dist/command-palette/useCommandShortcut.js.map +1 -0
  21. package/dist/date-picker/DatePicker.css +40 -0
  22. package/dist/date-picker/DatePicker.d.ts +2 -1
  23. package/dist/date-picker/DatePicker.d.ts.map +1 -1
  24. package/dist/date-picker/DatePicker.js +54 -8
  25. package/dist/date-picker/DatePicker.js.map +1 -1
  26. package/dist/date-picker/DatePicker.module.js +5 -1
  27. package/dist/date-picker/DatePicker.module.js.map +1 -1
  28. package/dist/dialog/Dialog.css +36 -2
  29. package/dist/dialog/Dialog.d.ts +15 -3
  30. package/dist/dialog/Dialog.d.ts.map +1 -1
  31. package/dist/dialog/Dialog.js +22 -14
  32. package/dist/dialog/Dialog.js.map +1 -1
  33. package/dist/dialog/Dialog.module.js +8 -2
  34. package/dist/dialog/Dialog.module.js.map +1 -1
  35. package/dist/dialog/tokens.d.ts +1 -1
  36. package/dist/dialog/tokens.d.ts.map +1 -1
  37. package/dist/dialog/tokens.js +2 -0
  38. package/dist/dialog/tokens.js.map +1 -1
  39. package/dist/field/Field.css +9 -0
  40. package/dist/field/Field.module.js.map +1 -1
  41. package/dist/index.d.ts +9 -2
  42. package/dist/index.d.ts.map +1 -1
  43. package/dist/index.js +10 -3
  44. package/dist/menu/Menu.css +84 -0
  45. package/dist/menu/Menu.d.ts +33 -6
  46. package/dist/menu/Menu.d.ts.map +1 -1
  47. package/dist/menu/Menu.js +110 -25
  48. package/dist/menu/Menu.js.map +1 -1
  49. package/dist/menu/Menu.module.js +22 -0
  50. package/dist/menu/Menu.module.js.map +1 -0
  51. package/dist/menu/tokens.d.ts +3 -0
  52. package/dist/menu/tokens.d.ts.map +1 -0
  53. package/dist/menu/tokens.js +31 -0
  54. package/dist/menu/tokens.js.map +1 -0
  55. package/dist/number-input/NumberInput.css +18 -0
  56. package/dist/number-input/NumberInput.js +1 -1
  57. package/dist/number-input/NumberInput.js.map +1 -1
  58. package/dist/number-input/NumberInput.module.js +3 -1
  59. package/dist/number-input/NumberInput.module.js.map +1 -1
  60. package/dist/pill-trigger/PillTrigger.css +104 -0
  61. package/dist/pill-trigger/PillTrigger.d.ts +20 -0
  62. package/dist/pill-trigger/PillTrigger.d.ts.map +1 -0
  63. package/dist/pill-trigger/PillTrigger.js +38 -0
  64. package/dist/pill-trigger/PillTrigger.js.map +1 -0
  65. package/dist/pill-trigger/PillTrigger.module.js +18 -0
  66. package/dist/pill-trigger/PillTrigger.module.js.map +1 -0
  67. package/dist/pill-trigger/tokens.d.ts +3 -0
  68. package/dist/pill-trigger/tokens.d.ts.map +1 -0
  69. package/dist/pill-trigger/tokens.js +37 -0
  70. package/dist/pill-trigger/tokens.js.map +1 -0
  71. package/dist/radio-group/RadioGroup.css +90 -0
  72. package/dist/radio-group/RadioGroup.d.ts +22 -3
  73. package/dist/radio-group/RadioGroup.d.ts.map +1 -1
  74. package/dist/radio-group/RadioGroup.js +42 -21
  75. package/dist/radio-group/RadioGroup.js.map +1 -1
  76. package/dist/radio-group/RadioGroup.module.js +12 -2
  77. package/dist/radio-group/RadioGroup.module.js.map +1 -1
  78. package/dist/radio-group/tokens.d.ts +2 -2
  79. package/dist/radio-group/tokens.d.ts.map +1 -1
  80. package/dist/radio-group/tokens.js +22 -2
  81. package/dist/radio-group/tokens.js.map +1 -1
  82. package/dist/segmented-control/SegmentedControl.css +83 -0
  83. package/dist/segmented-control/SegmentedControl.d.ts +35 -0
  84. package/dist/segmented-control/SegmentedControl.d.ts.map +1 -0
  85. package/dist/segmented-control/SegmentedControl.js +44 -0
  86. package/dist/segmented-control/SegmentedControl.js.map +1 -0
  87. package/dist/segmented-control/SegmentedControl.module.js +16 -0
  88. package/dist/segmented-control/SegmentedControl.module.js.map +1 -0
  89. package/dist/segmented-control/tokens.d.ts +3 -0
  90. package/dist/segmented-control/tokens.d.ts.map +1 -0
  91. package/dist/segmented-control/tokens.js +29 -0
  92. package/dist/segmented-control/tokens.js.map +1 -0
  93. package/dist/select/ListBox.css +23 -1
  94. package/dist/select/ListBox.module.js +2 -2
  95. package/dist/select/ListBox.module.js.map +1 -1
  96. package/dist/select/listBoxTokens.d.ts +1 -1
  97. package/dist/select/listBoxTokens.d.ts.map +1 -1
  98. package/dist/select/listBoxTokens.js +2 -0
  99. package/dist/select/listBoxTokens.js.map +1 -1
  100. package/dist/slider/Slider.css +84 -0
  101. package/dist/slider/Slider.d.ts +20 -0
  102. package/dist/slider/Slider.d.ts.map +1 -0
  103. package/dist/slider/Slider.js +70 -0
  104. package/dist/slider/Slider.js.map +1 -0
  105. package/dist/slider/Slider.module.js +20 -0
  106. package/dist/slider/Slider.module.js.map +1 -0
  107. package/dist/tags-input/TagsInput.css +60 -0
  108. package/dist/tags-input/TagsInput.d.ts +32 -0
  109. package/dist/tags-input/TagsInput.d.ts.map +1 -0
  110. package/dist/tags-input/TagsInput.js +160 -0
  111. package/dist/tags-input/TagsInput.js.map +1 -0
  112. package/dist/tags-input/TagsInput.module.js +20 -0
  113. package/dist/tags-input/TagsInput.module.js.map +1 -0
  114. package/dist/text-input/TextInput.d.ts.map +1 -1
  115. package/dist/text-input/TextInput.js +2 -0
  116. package/dist/text-input/TextInput.js.map +1 -1
  117. package/dist/theme/components.d.ts +7 -3
  118. package/dist/theme/components.d.ts.map +1 -1
  119. package/dist/theme/components.js +8 -0
  120. package/dist/theme/components.js.map +1 -1
  121. package/package.json +3 -3
@@ -0,0 +1,3 @@
1
+ /** Tokens of SegmentedControl. */
2
+ export declare const segmentedControlTokens: import("..").ComponentTokens<"segmented-control", "panneau-segmented-control-radius" | "panneau-segmented-control-padding" | "panneau-segmented-control-bg" | "panneau-segmented-control-border-color" | "panneau-segmented-control-segment-padding-x" | "panneau-segmented-control-segment-font-weight" | "panneau-segmented-control-segment-color" | "panneau-segmented-control-segment-color-selected" | "panneau-segmented-control-segment-bg-selected" | "panneau-segmented-control-segment-shadow-selected">;
3
+ //# sourceMappingURL=tokens.d.ts.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"tokens.d.ts","sourceRoot":"","sources":["../../src/segmented-control/tokens.ts"],"names":[],"mappings":"AAEA,kCAAkC;AAClC,eAAO,MAAM,sBAAsB,ofAqBjC,CAAC"}
@@ -0,0 +1,29 @@
1
+ import { defineComponentTokens } from "../theme/componentTokens.js";
2
+ //#region src/segmented-control/tokens.ts
3
+ /** Tokens of SegmentedControl. */
4
+ var segmentedControlTokens = defineComponentTokens("segmented-control", {
5
+ /** Background of the group, behind the segments. */
6
+ bg: "var(--panneau-color-surface-sunken)",
7
+ /** Color of the border around the group. */
8
+ "border-color": "var(--panneau-color-border)",
9
+ /** Corner radius of the group. */
10
+ radius: "var(--panneau-radius-md)",
11
+ /** Space between the group's border and its segments. */
12
+ padding: "2px",
13
+ /** Horizontal padding of a segment. */
14
+ "segment-padding-x": "var(--panneau-space-3)",
15
+ /** Font weight of a segment. */
16
+ "segment-font-weight": "var(--panneau-font-weight-medium)",
17
+ /** Text color of a segment. */
18
+ "segment-color": "var(--panneau-color-text-muted)",
19
+ /** Text color of the selected segment, and of a hovered one. */
20
+ "segment-color-selected": "var(--panneau-color-text)",
21
+ /** Background of the selected segment. */
22
+ "segment-bg-selected": "var(--panneau-color-surface-raised)",
23
+ /** Shadow of the selected segment. */
24
+ "segment-shadow-selected": "var(--panneau-shadow-sm)"
25
+ });
26
+ //#endregion
27
+ export { segmentedControlTokens };
28
+
29
+ //# sourceMappingURL=tokens.js.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"tokens.js","names":[],"sources":["../../src/segmented-control/tokens.ts"],"sourcesContent":["import { defineComponentTokens } from '../theme/componentTokens';\n\n/** Tokens of SegmentedControl. */\nexport const segmentedControlTokens = defineComponentTokens('segmented-control', {\n /** Background of the group, behind the segments. */\n bg: 'var(--panneau-color-surface-sunken)',\n /** Color of the border around the group. */\n 'border-color': 'var(--panneau-color-border)',\n /** Corner radius of the group. */\n radius: 'var(--panneau-radius-md)',\n /** Space between the group's border and its segments. */\n padding: '2px',\n /** Horizontal padding of a segment. */\n 'segment-padding-x': 'var(--panneau-space-3)',\n /** Font weight of a segment. */\n 'segment-font-weight': 'var(--panneau-font-weight-medium)',\n /** Text color of a segment. */\n 'segment-color': 'var(--panneau-color-text-muted)',\n /** Text color of the selected segment, and of a hovered one. */\n 'segment-color-selected': 'var(--panneau-color-text)',\n /** Background of the selected segment. */\n 'segment-bg-selected': 'var(--panneau-color-surface-raised)',\n /** Shadow of the selected segment. */\n 'segment-shadow-selected': 'var(--panneau-shadow-sm)',\n});\n"],"mappings":";;;AAGA,IAAa,yBAAyB,sBAAsB,qBAAqB;;CAE7E,IAAI;;CAEJ,gBAAgB;;CAEhB,QAAQ;;CAER,SAAS;;CAET,qBAAqB;;CAErB,uBAAuB;;CAEvB,iBAAiB;;CAEjB,0BAA0B;;CAE1B,uBAAuB;;CAEvB,2BAA2B;AAC/B,CAAC"}
@@ -47,15 +47,22 @@
47
47
  display: flex;
48
48
  flex: 1 1 auto;
49
49
  flex-direction: column;
50
+ gap: 0.125rem;
50
51
  min-width: 0;
51
52
  }
52
53
 
54
+ /* An option with a description has two lines: more room above and below them. */
55
+ .panneau-list-box-item:has(.panneau-list-box-item-description) {
56
+ padding-block: var(--panneau-list-box-item-padding-y-described, var(--panneau-space-2));
57
+ }
58
+
53
59
  .panneau-list-box-item-label {
54
60
  overflow-wrap: anywhere;
55
61
  }
56
62
 
57
63
  .panneau-list-box-item-description {
58
- font-size: var(--panneau-font-size-sm);
64
+ font-size: var(--panneau-font-size-xs);
65
+ line-height: var(--panneau-line-height-tight);
59
66
  color: var(--panneau-color-text-muted);
60
67
  }
61
68
 
@@ -96,6 +103,21 @@
96
103
  white-space: nowrap;
97
104
  }
98
105
 
106
+ /* The chosen option, in the trigger: its description follows its label on the same line. */
107
+ .panneau-list-box-value .panneau-list-box-item-text {
108
+ flex-direction: row;
109
+ align-items: baseline;
110
+ gap: var(--panneau-space-2);
111
+ }
112
+
113
+ .panneau-list-box-value .panneau-list-box-item-label,
114
+ .panneau-list-box-value .panneau-list-box-item-description {
115
+ flex: 0 1 auto;
116
+ overflow: hidden;
117
+ text-overflow: ellipsis;
118
+ white-space: nowrap;
119
+ }
120
+
99
121
  .panneau-list-box-value[data-placeholder] {
100
122
  color: var(--panneau-color-text-muted);
101
123
  }
@@ -3,8 +3,8 @@ import "./ListBox.css";
3
3
  var listBox = "panneau-list-box";
4
4
  var item = "panneau-list-box-item";
5
5
  var itemText = "panneau-list-box-item-text";
6
- var itemLabel = "panneau-list-box-item-label";
7
6
  var itemDescription = "panneau-list-box-item-description";
7
+ var itemLabel = "panneau-list-box-item-label";
8
8
  var check = "panneau-list-box-check";
9
9
  var placeholder = "panneau-list-box-placeholder";
10
10
  var empty = "panneau-list-box-empty";
@@ -16,8 +16,8 @@ var ListBox_module_default = {
16
16
  listBox,
17
17
  item,
18
18
  itemText,
19
- itemLabel,
20
19
  itemDescription,
20
+ itemLabel,
21
21
  check,
22
22
  placeholder,
23
23
  empty,
@@ -1 +1 @@
1
- {"version":3,"file":"ListBox.module.js","names":[],"sources":["../../src/select/ListBox.module.css"],"sourcesContent":["/* Options of selects, combo boxes and menus. */\n\n.listBox {\n display: flex;\n flex-direction: column;\n max-height: inherit;\n padding: var(--panneau-list-box-padding, var(--panneau-space-1));\n overflow: auto;\n outline: none;\n}\n\n.item {\n display: flex;\n align-items: center;\n gap: var(--panneau-space-2);\n min-height: var(--panneau-control-height-sm);\n padding: var(--panneau-list-box-item-padding-y, calc(var(--panneau-row-padding-y) / 2))\n var(--panneau-list-box-item-padding-x, var(--panneau-space-2));\n font-size: var(--panneau-font-size-control);\n line-height: var(--panneau-line-height-tight);\n color: var(--panneau-color-text);\n cursor: default;\n border-radius: var(--panneau-list-box-item-radius, var(--panneau-radius-sm));\n outline: none;\n}\n\n.item[data-focused],\n.item[data-hovered] {\n background-color: var(--panneau-list-box-item-bg-hover, var(--panneau-color-hover));\n}\n\n.item[data-focus-visible] {\n outline: var(--panneau-focus-width) solid var(--panneau-color-focus);\n outline-offset: -2px;\n}\n\n.item[data-disabled] {\n cursor: not-allowed;\n opacity: 0.5;\n}\n\n.item[data-danger] {\n color: var(--panneau-color-danger);\n}\n\n.itemText {\n display: flex;\n flex: 1 1 auto;\n flex-direction: column;\n min-width: 0;\n}\n\n.itemLabel {\n overflow-wrap: anywhere;\n}\n\n.itemDescription {\n font-size: var(--panneau-font-size-sm);\n color: var(--panneau-color-text-muted);\n}\n\n.check {\n flex: 0 0 auto;\n width: 1rem;\n color: var(--panneau-color-text);\n}\n\n.placeholder {\n color: var(--panneau-color-text-muted);\n}\n\n.empty {\n padding: var(--panneau-space-2);\n font-size: var(--panneau-font-size-sm);\n color: var(--panneau-color-text-muted);\n}\n\n.separator {\n height: 1px;\n margin: var(--panneau-space-1) 0;\n background-color: var(--panneau-color-border);\n}\n\n.trigger {\n justify-content: space-between;\n gap: var(--panneau-space-2);\n text-align: start;\n cursor: pointer;\n}\n\n.value {\n flex: 1 1 auto;\n min-width: 0;\n overflow: hidden;\n text-overflow: ellipsis;\n white-space: nowrap;\n}\n\n.value[data-placeholder] {\n color: var(--panneau-color-text-muted);\n}\n\n.chevron {\n color: var(--panneau-color-text-muted);\n}\n"],"mappings":""}
1
+ {"version":3,"file":"ListBox.module.js","names":[],"sources":["../../src/select/ListBox.module.css"],"sourcesContent":["/* Options of selects, combo boxes and menus. */\n\n.listBox {\n display: flex;\n flex-direction: column;\n max-height: inherit;\n padding: var(--panneau-list-box-padding, var(--panneau-space-1));\n overflow: auto;\n outline: none;\n}\n\n.item {\n display: flex;\n align-items: center;\n gap: var(--panneau-space-2);\n min-height: var(--panneau-control-height-sm);\n padding: var(--panneau-list-box-item-padding-y, calc(var(--panneau-row-padding-y) / 2))\n var(--panneau-list-box-item-padding-x, var(--panneau-space-2));\n font-size: var(--panneau-font-size-control);\n line-height: var(--panneau-line-height-tight);\n color: var(--panneau-color-text);\n cursor: default;\n border-radius: var(--panneau-list-box-item-radius, var(--panneau-radius-sm));\n outline: none;\n}\n\n.item[data-focused],\n.item[data-hovered] {\n background-color: var(--panneau-list-box-item-bg-hover, var(--panneau-color-hover));\n}\n\n.item[data-focus-visible] {\n outline: var(--panneau-focus-width) solid var(--panneau-color-focus);\n outline-offset: -2px;\n}\n\n.item[data-disabled] {\n cursor: not-allowed;\n opacity: 0.5;\n}\n\n.item[data-danger] {\n color: var(--panneau-color-danger);\n}\n\n.itemText {\n display: flex;\n flex: 1 1 auto;\n flex-direction: column;\n gap: 0.125rem;\n min-width: 0;\n}\n\n/* An option with a description has two lines: more room above and below them. */\n.item:has(.itemDescription) {\n padding-block: var(--panneau-list-box-item-padding-y-described, var(--panneau-space-2));\n}\n\n.itemLabel {\n overflow-wrap: anywhere;\n}\n\n.itemDescription {\n font-size: var(--panneau-font-size-xs);\n line-height: var(--panneau-line-height-tight);\n color: var(--panneau-color-text-muted);\n}\n\n.check {\n flex: 0 0 auto;\n width: 1rem;\n color: var(--panneau-color-text);\n}\n\n.placeholder {\n color: var(--panneau-color-text-muted);\n}\n\n.empty {\n padding: var(--panneau-space-2);\n font-size: var(--panneau-font-size-sm);\n color: var(--panneau-color-text-muted);\n}\n\n.separator {\n height: 1px;\n margin: var(--panneau-space-1) 0;\n background-color: var(--panneau-color-border);\n}\n\n.trigger {\n justify-content: space-between;\n gap: var(--panneau-space-2);\n text-align: start;\n cursor: pointer;\n}\n\n.value {\n flex: 1 1 auto;\n min-width: 0;\n overflow: hidden;\n text-overflow: ellipsis;\n white-space: nowrap;\n}\n\n/* The chosen option, in the trigger: its description follows its label on the same line. */\n.value .itemText {\n flex-direction: row;\n align-items: baseline;\n gap: var(--panneau-space-2);\n}\n\n.value .itemLabel,\n.value .itemDescription {\n flex: 0 1 auto;\n overflow: hidden;\n text-overflow: ellipsis;\n white-space: nowrap;\n}\n\n.value[data-placeholder] {\n color: var(--panneau-color-text-muted);\n}\n\n.chevron {\n color: var(--panneau-color-text-muted);\n}\n"],"mappings":""}
@@ -1,3 +1,3 @@
1
1
  /** Tokens of the options of `Select`, `ComboBox` and `Menu`. */
2
- export declare const listBoxTokens: import("..").ComponentTokens<"list-box", "panneau-list-box-padding" | "panneau-list-box-item-padding-y" | "panneau-list-box-item-padding-x" | "panneau-list-box-item-radius" | "panneau-list-box-item-bg-hover">;
2
+ export declare const listBoxTokens: import("..").ComponentTokens<"list-box", "panneau-list-box-padding" | "panneau-list-box-item-radius" | "panneau-list-box-item-padding-y" | "panneau-list-box-item-padding-y-described" | "panneau-list-box-item-padding-x" | "panneau-list-box-item-bg-hover">;
3
3
  //# sourceMappingURL=listBoxTokens.d.ts.map
@@ -1 +1 @@
1
- {"version":3,"file":"listBoxTokens.d.ts","sourceRoot":"","sources":["../../src/select/listBoxTokens.ts"],"names":[],"mappings":"AAEA,gEAAgE;AAChE,eAAO,MAAM,aAAa,kNAWxB,CAAC"}
1
+ {"version":3,"file":"listBoxTokens.d.ts","sourceRoot":"","sources":["../../src/select/listBoxTokens.ts"],"names":[],"mappings":"AAEA,gEAAgE;AAChE,eAAO,MAAM,aAAa,gQAaxB,CAAC"}
@@ -6,6 +6,8 @@ var listBoxTokens = defineComponentTokens("list-box", {
6
6
  padding: "var(--panneau-space-1)",
7
7
  /** Vertical padding of an option. */
8
8
  "item-padding-y": "calc(var(--panneau-row-padding-y) / 2)",
9
+ /** Vertical padding of an option with a description, on two lines. */
10
+ "item-padding-y-described": "var(--panneau-space-2)",
9
11
  /** Horizontal padding of an option. */
10
12
  "item-padding-x": "var(--panneau-space-2)",
11
13
  /** Corner radius of an option. */
@@ -1 +1 @@
1
- {"version":3,"file":"listBoxTokens.js","names":[],"sources":["../../src/select/listBoxTokens.ts"],"sourcesContent":["import { defineComponentTokens } from '../theme/componentTokens';\n\n/** Tokens of the options of `Select`, `ComboBox` and `Menu`. */\nexport const listBoxTokens = defineComponentTokens('list-box', {\n /** Padding around the options. */\n padding: 'var(--panneau-space-1)',\n /** Vertical padding of an option. */\n 'item-padding-y': 'calc(var(--panneau-row-padding-y) / 2)',\n /** Horizontal padding of an option. */\n 'item-padding-x': 'var(--panneau-space-2)',\n /** Corner radius of an option. */\n 'item-radius': 'var(--panneau-radius-sm)',\n /** Background of a focused or hovered option. */\n 'item-bg-hover': 'var(--panneau-color-hover)',\n});\n"],"mappings":";;;AAGA,IAAa,gBAAgB,sBAAsB,YAAY;;CAE3D,SAAS;;CAET,kBAAkB;;CAElB,kBAAkB;;CAElB,eAAe;;CAEf,iBAAiB;AACrB,CAAC"}
1
+ {"version":3,"file":"listBoxTokens.js","names":[],"sources":["../../src/select/listBoxTokens.ts"],"sourcesContent":["import { defineComponentTokens } from '../theme/componentTokens';\n\n/** Tokens of the options of `Select`, `ComboBox` and `Menu`. */\nexport const listBoxTokens = defineComponentTokens('list-box', {\n /** Padding around the options. */\n padding: 'var(--panneau-space-1)',\n /** Vertical padding of an option. */\n 'item-padding-y': 'calc(var(--panneau-row-padding-y) / 2)',\n /** Vertical padding of an option with a description, on two lines. */\n 'item-padding-y-described': 'var(--panneau-space-2)',\n /** Horizontal padding of an option. */\n 'item-padding-x': 'var(--panneau-space-2)',\n /** Corner radius of an option. */\n 'item-radius': 'var(--panneau-radius-sm)',\n /** Background of a focused or hovered option. */\n 'item-bg-hover': 'var(--panneau-color-hover)',\n});\n"],"mappings":";;;AAGA,IAAa,gBAAgB,sBAAsB,YAAY;;CAE3D,SAAS;;CAET,kBAAkB;;CAElB,4BAA4B;;CAE5B,kBAAkB;;CAElB,eAAe;;CAEf,iBAAiB;AACrB,CAAC"}
@@ -0,0 +1,84 @@
1
+ /* A track with the part before the thumb filled, and the value next to the label. */
2
+
3
+ .panneau-slider {
4
+ width: 100%;
5
+ }
6
+
7
+ .panneau-slider-header {
8
+ display: flex;
9
+ align-items: baseline;
10
+ justify-content: space-between;
11
+ gap: var(--panneau-space-2);
12
+ }
13
+
14
+ .panneau-slider-output {
15
+ font-size: var(--panneau-font-size-sm);
16
+ font-variant-numeric: var(--panneau-font-numeric);
17
+ color: var(--panneau-color-text-muted);
18
+ }
19
+
20
+ .panneau-slider-track {
21
+ position: relative;
22
+ height: var(--panneau-control-height-sm);
23
+ cursor: pointer;
24
+ }
25
+
26
+ /* The rail, centered in the track. */
27
+ .panneau-slider-track::before {
28
+ position: absolute;
29
+ top: 50%;
30
+ right: 0;
31
+ left: 0;
32
+ height: 0.25rem;
33
+ content: '';
34
+ background-color: var(--panneau-color-surface-sunken);
35
+ border: var(--panneau-border-width) solid var(--panneau-color-border);
36
+ border-radius: var(--panneau-radius-full);
37
+ transform: translateY(-50%);
38
+ }
39
+
40
+ .panneau-slider-fill {
41
+ position: absolute;
42
+ top: 50%;
43
+ left: 0;
44
+ height: 0.25rem;
45
+ background-color: var(--panneau-color-accent);
46
+ border-radius: var(--panneau-radius-full);
47
+ transform: translateY(-50%);
48
+ }
49
+
50
+ .panneau-slider-thumb {
51
+ top: 50%;
52
+ width: 1.125rem;
53
+ height: 1.125rem;
54
+ background-color: var(--panneau-color-surface);
55
+ border: 2px solid var(--panneau-color-accent);
56
+ border-radius: var(--panneau-radius-full);
57
+ box-shadow: var(--panneau-shadow-sm);
58
+ transform: translateY(-50%);
59
+ }
60
+
61
+ .panneau-slider[data-empty] .panneau-slider-thumb {
62
+ border-color: var(--panneau-color-border-control);
63
+ }
64
+
65
+ .panneau-slider-thumb[data-dragging] {
66
+ background-color: var(--panneau-color-accent);
67
+ }
68
+
69
+ .panneau-slider-thumb[data-focus-visible] {
70
+ outline: var(--panneau-focus-width) solid var(--panneau-color-focus);
71
+ outline-offset: 2px;
72
+ }
73
+
74
+ .panneau-slider[data-invalid] .panneau-slider-thumb {
75
+ border-color: var(--panneau-color-danger);
76
+ }
77
+
78
+ .panneau-slider[data-disabled] {
79
+ opacity: 0.6;
80
+ }
81
+
82
+ .panneau-slider[data-disabled] .panneau-slider-track {
83
+ cursor: not-allowed;
84
+ }
@@ -0,0 +1,20 @@
1
+ import { type ReactNode } from 'react';
2
+ import { type SliderProps as AriaSliderProps } from 'react-aria-components';
3
+ import { type FieldChromeProps } from '../field/FieldParts';
4
+ export interface SliderProps extends Omit<AriaSliderProps<number>, 'className' | 'style' | 'children' | 'value' | 'defaultValue' | 'onChange'>, FieldChromeProps {
5
+ /** The number, or `null` until the slider is moved: the thumb then rests at the start. */
6
+ value?: number | null;
7
+ defaultValue?: number | null;
8
+ onChange?: (value: number) => void;
9
+ /** Content after the value: a unit. */
10
+ suffix?: ReactNode;
11
+ /** Name of the input, in a form. */
12
+ name?: string;
13
+ isRequired?: boolean;
14
+ }
15
+ /**
16
+ * A number between `minValue` and `maxValue` (0 and 100 by default), picked on a track by mouse,
17
+ * touch or arrow keys. Its value shows next to its label, formatted for the locale.
18
+ */
19
+ export declare function Slider({ label, description, errors, value, defaultValue, onChange, suffix, name, isRequired, minValue, maxValue, className, labelClassName, descriptionClassName, errorsClassName, ...props }: SliderProps): import("react").JSX.Element;
20
+ //# sourceMappingURL=Slider.d.ts.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"Slider.d.ts","sourceRoot":"","sources":["../../src/slider/Slider.tsx"],"names":[],"mappings":"AAAA,OAAO,EAAE,KAAK,SAAS,EAAS,MAAM,OAAO,CAAC;AAC9C,OAAO,EAEH,KAAK,WAAW,IAAI,eAAe,EAItC,MAAM,uBAAuB,CAAC;AAE/B,OAAO,EAAE,KAAK,gBAAgB,EAA2B,MAAM,qBAAqB,CAAC;AAIrF,MAAM,WAAW,WACb,SACI,IAAI,CACA,eAAe,CAAC,MAAM,CAAC,EACvB,WAAW,GAAG,OAAO,GAAG,UAAU,GAAG,OAAO,GAAG,cAAc,GAAG,UAAU,CAC7E,EACD,gBAAgB;IACpB,0FAA0F;IAC1F,KAAK,CAAC,EAAE,MAAM,GAAG,IAAI,CAAC;IACtB,YAAY,CAAC,EAAE,MAAM,GAAG,IAAI,CAAC;IAC7B,QAAQ,CAAC,EAAE,CAAC,KAAK,EAAE,MAAM,KAAK,IAAI,CAAC;IACnC,uCAAuC;IACvC,MAAM,CAAC,EAAE,SAAS,CAAC;IACnB,oCAAoC;IACpC,IAAI,CAAC,EAAE,MAAM,CAAC;IACd,UAAU,CAAC,EAAE,OAAO,CAAC;CACxB;AAED;;;GAGG;AACH,wBAAgB,MAAM,CAAC,EACnB,KAAK,EACL,WAAW,EACX,MAAW,EACX,KAAK,EACL,YAAY,EACZ,QAAQ,EACR,MAAM,EACN,IAAI,EACJ,UAAU,EACV,QAAY,EACZ,QAAc,EACd,SAAS,EACT,cAAc,EACd,oBAAoB,EACpB,eAAe,EACf,GAAG,KAAK,EACX,EAAE,WAAW,+BAyEb"}
@@ -0,0 +1,70 @@
1
+ import { cx } from "../utils/cx.js";
2
+ import Field_module_default from "../field/Field.module.js";
3
+ import { FieldLabel } from "../field/FieldParts.js";
4
+ import Slider_module_default from "./Slider.module.js";
5
+ import { Slider, SliderOutput, SliderThumb, SliderTrack } from "react-aria-components";
6
+ import { Fragment, jsx, jsxs } from "react/jsx-runtime";
7
+ import { useId } from "react";
8
+ //#region src/slider/Slider.tsx
9
+ /**
10
+ * A number between `minValue` and `maxValue` (0 and 100 by default), picked on a track by mouse,
11
+ * touch or arrow keys. Its value shows next to its label, formatted for the locale.
12
+ */
13
+ function Slider$1({ label, description, errors = [], value, defaultValue, onChange, suffix, name, isRequired, minValue = 0, maxValue = 100, className, labelClassName, descriptionClassName, errorsClassName, ...props }) {
14
+ const id = useId();
15
+ const invalid = errors.length > 0;
16
+ const describedBy = [description !== void 0 && description !== null ? `${id}-description` : null, invalid ? `${id}-errors` : null].filter((part) => part !== null).join(" ");
17
+ const empty = value === null || value === void 0 && defaultValue == null;
18
+ return /* @__PURE__ */ jsxs(Slider, {
19
+ ...props,
20
+ minValue,
21
+ maxValue,
22
+ ...value !== void 0 ? { value: value ?? minValue } : {},
23
+ ...defaultValue !== void 0 ? { defaultValue: defaultValue ?? minValue } : {},
24
+ ...onChange !== void 0 ? { onChange } : {},
25
+ className: cx("panneau-slider", Field_module_default.field, Slider_module_default.slider, className),
26
+ "data-invalid": invalid || void 0,
27
+ "data-empty": empty || void 0,
28
+ children: [
29
+ /* @__PURE__ */ jsxs("div", {
30
+ className: Slider_module_default.header,
31
+ children: [/* @__PURE__ */ jsx(FieldLabel, {
32
+ isRequired,
33
+ className: labelClassName,
34
+ children: label
35
+ }), /* @__PURE__ */ jsx(SliderOutput, {
36
+ className: Slider_module_default.output,
37
+ children: ({ state }) => empty ? "—" : /* @__PURE__ */ jsxs(Fragment, { children: [state.getThumbValueLabel(0), suffix !== void 0 ? /* @__PURE__ */ jsxs(Fragment, { children: [" ", suffix] }) : null] })
38
+ })]
39
+ }),
40
+ /* @__PURE__ */ jsx(SliderTrack, {
41
+ className: Slider_module_default.track,
42
+ children: ({ state: state_0 }) => /* @__PURE__ */ jsxs(Fragment, { children: [/* @__PURE__ */ jsx("div", {
43
+ className: Slider_module_default.fill,
44
+ style: { width: empty ? 0 : `${state_0.getThumbPercent(0) * 100}%` }
45
+ }), /* @__PURE__ */ jsx(SliderThumb, {
46
+ className: Slider_module_default.thumb,
47
+ ...name !== void 0 ? { name } : {},
48
+ ...describedBy !== "" ? { "aria-describedby": describedBy } : {}
49
+ })] })
50
+ }),
51
+ description !== void 0 && description !== null ? /* @__PURE__ */ jsx("div", {
52
+ id: `${id}-description`,
53
+ className: cx(Field_module_default.description, descriptionClassName),
54
+ children: description
55
+ }) : null,
56
+ invalid ? /* @__PURE__ */ jsx("div", {
57
+ id: `${id}-errors`,
58
+ className: cx(Field_module_default.errors, errorsClassName),
59
+ children: errors.map((error, index) => /* @__PURE__ */ jsx("span", {
60
+ className: Field_module_default.error,
61
+ children: error
62
+ }, index))
63
+ }) : null
64
+ ]
65
+ });
66
+ }
67
+ //#endregion
68
+ export { Slider$1 as Slider };
69
+
70
+ //# sourceMappingURL=Slider.js.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"Slider.js","names":["state","Slider","AriaSlider","fieldStyles","styles","_Fragment"],"sources":["../../src/slider/Slider.tsx"],"sourcesContent":["import { type ReactNode, useId } from 'react';\nimport {\n Slider as AriaSlider,\n type SliderProps as AriaSliderProps,\n SliderOutput,\n SliderThumb,\n SliderTrack,\n} from 'react-aria-components';\n\nimport { type FieldChromeProps, FieldLabel, fieldStyles } from '../field/FieldParts';\nimport { cx } from '../utils/cx';\nimport styles from './Slider.module.css';\n\nexport interface SliderProps\n extends\n Omit<\n AriaSliderProps<number>,\n 'className' | 'style' | 'children' | 'value' | 'defaultValue' | 'onChange'\n >,\n FieldChromeProps {\n /** The number, or `null` until the slider is moved: the thumb then rests at the start. */\n value?: number | null;\n defaultValue?: number | null;\n onChange?: (value: number) => void;\n /** Content after the value: a unit. */\n suffix?: ReactNode;\n /** Name of the input, in a form. */\n name?: string;\n isRequired?: boolean;\n}\n\n/**\n * A number between `minValue` and `maxValue` (0 and 100 by default), picked on a track by mouse,\n * touch or arrow keys. Its value shows next to its label, formatted for the locale.\n */\nexport function Slider({\n label,\n description,\n errors = [],\n value,\n defaultValue,\n onChange,\n suffix,\n name,\n isRequired,\n minValue = 0,\n maxValue = 100,\n className,\n labelClassName,\n descriptionClassName,\n errorsClassName,\n ...props\n}: SliderProps) {\n const id = useId();\n const invalid = errors.length > 0;\n const describedBy = [\n description !== undefined && description !== null ? `${id}-description` : null,\n invalid ? `${id}-errors` : null,\n ]\n .filter((part) => part !== null)\n .join(' ');\n const empty = value === null || (value === undefined && defaultValue == null);\n return (\n <AriaSlider\n {...props}\n minValue={minValue}\n maxValue={maxValue}\n {...(value !== undefined ? { value: value ?? minValue } : {})}\n {...(defaultValue !== undefined ? { defaultValue: defaultValue ?? minValue } : {})}\n {...(onChange !== undefined ? { onChange } : {})}\n className={cx('panneau-slider', fieldStyles.field, styles.slider, className)}\n data-invalid={invalid || undefined}\n data-empty={empty || undefined}\n >\n <div className={styles.header}>\n <FieldLabel isRequired={isRequired} className={labelClassName}>\n {label}\n </FieldLabel>\n <SliderOutput className={styles.output}>\n {({ state }) =>\n empty ? (\n '—'\n ) : (\n <>\n {state.getThumbValueLabel(0)}\n {suffix !== undefined ? <> {suffix}</> : null}\n </>\n )\n }\n </SliderOutput>\n </div>\n <SliderTrack className={styles.track}>\n {({ state }) => (\n <>\n <div\n className={styles.fill}\n style={{ width: empty ? 0 : `${state.getThumbPercent(0) * 100}%` }}\n />\n <SliderThumb\n className={styles.thumb}\n {...(name !== undefined ? { name } : {})}\n {...(describedBy !== '' ? { 'aria-describedby': describedBy } : {})}\n />\n </>\n )}\n </SliderTrack>\n {description !== undefined && description !== null ? (\n <div\n id={`${id}-description`}\n className={cx(fieldStyles.description, descriptionClassName)}\n >\n {description}\n </div>\n ) : null}\n {invalid ? (\n <div id={`${id}-errors`} className={cx(fieldStyles.errors, errorsClassName)}>\n {errors.map((error, index) => (\n <span key={index} className={fieldStyles.error}>\n {error}\n </span>\n ))}\n </div>\n ) : null}\n </AriaSlider>\n );\n}\n"],"mappings":";;;;;;;;;;;;AAmCA,SAAgBC,SAAO,EACnB,OACA,aACA,SAAS,CAAA,GACT,OACA,cACA,UACA,QACA,MACA,YACA,WAAW,GACX,WAAW,KACX,WACA,gBACA,sBACA,iBACA,GAAG,SACS;CACZ,MAAM,KAAK,MAAM;CACjB,MAAM,UAAU,OAAO,SAAS;CAChC,MAAM,cAAc,CAChB,gBAAgB,KAAA,KAAa,gBAAgB,OAAO,GAAG,GAAE,gBAAiB,MAC1E,UAAU,GAAG,GAAE,WAAY,IAAI,CAClC,CACI,QAAQ,SAAS,SAAS,IAAI,CAAC,CAC/B,KAAK,GAAG;CACb,MAAM,QAAQ,UAAU,QAAS,UAAU,KAAA,KAAa,gBAAgB;CACxE,OACI,qBAACC,QAAD;EACI,GAAI;EACM;EACA;EACV,GAAK,UAAU,KAAA,IAAY,EAAE,OAAO,SAAS,SAAS,IAAI,CAAC;EAC3D,GAAK,iBAAiB,KAAA,IAAY,EAAE,cAAc,gBAAgB,SAAS,IAAI,CAAC;EAChF,GAAK,aAAa,KAAA,IAAY,EAAE,SAAS,IAAI,CAAC;EAC9C,WAAW,GAAG,kBAAkBC,qBAAY,OAAOC,sBAAO,QAAQ,SAAS;EAC3E,gBAAc,WAAW,KAAA;EACzB,cAAY,SAAS,KAAA;EATzB,UAAA;GAWI,qBAAC,OAAD;IAAK,WAAWA,sBAAO;IAAvB,UAAA,CACI,oBAAC,YAAD;KAAwB;KAAY,WAAW;KAC1C,UAAA;IACO,CAAA,GACZ,oBAAC,cAAD;KAAc,WAAWA,sBAAO;KAC1B,WAAA,EAAE,YACA,QACI,MAEA,qBAAAC,UAAA,EAAA,UAAA,CACK,MAAM,mBAAmB,CAAC,GAC1B,WAAW,KAAA,IAAY,qBAAAA,UAAA,EAAA,UAAA,CAAE,KAAE,MAAO,EAAA,CAAA,IAAM,IAC7C,EAAA,CAAA;IAGE,CAAA,CACb;;GACL,oBAAC,aAAD;IAAa,WAAWD,sBAAO;IACzB,WAAA,EAAE,OAAAJ,cACA,qBAAAK,UAAA,EAAA,UAAA,CACI,oBAAC,OAAD;KACI,WAAWD,sBAAO;KAClB,OAAO,EAAE,OAAO,QAAQ,IAAI,GAAGJ,QAAM,gBAAgB,CAAC,IAAI,IAAG,GAAI;IAAE,CAAA,GAEvE,oBAAC,aAAD;KACI,WAAWI,sBAAO;KAClB,GAAK,SAAS,KAAA,IAAY,EAAE,KAAK,IAAI,CAAC;KACtC,GAAK,gBAAgB,KAAK,EAAE,oBAAoB,YAAY,IAAI,CAAC;IAAG,CAAA,CAE5E,EAAA,CAAA;GAEK,CAAA;GACZ,gBAAgB,KAAA,KAAa,gBAAgB,OAC1C,oBAAC,OAAD;IACI,IAAI,GAAG,GAAE;IACT,WAAW,GAAGD,qBAAY,aAAa,oBAAoB;IAE1D,UAAA;GACA,CAAA,IACL;GACH,UACG,oBAAC,OAAD;IAAK,IAAI,GAAG,GAAE;IAAW,WAAW,GAAGA,qBAAY,QAAQ,eAAe;IACrE,UAAA,OAAO,KAAK,OAAO,UAChB,oBAAC,QAAD;KAAkB,WAAWA,qBAAY;KACpC,UAAA;IACC,GAFK,KAEL,CACT;GACA,CAAA,IACL;EACI;;AAEpB"}
@@ -0,0 +1,20 @@
1
+ import "./Slider.css";
2
+ //#region src/slider/Slider.module.css
3
+ var slider = "panneau-slider";
4
+ var header = "panneau-slider-header";
5
+ var output = "panneau-slider-output";
6
+ var track = "panneau-slider-track";
7
+ var fill = "panneau-slider-fill";
8
+ var thumb = "panneau-slider-thumb";
9
+ var Slider_module_default = {
10
+ slider,
11
+ header,
12
+ output,
13
+ track,
14
+ fill,
15
+ thumb
16
+ };
17
+ //#endregion
18
+ export { Slider_module_default as default, fill, header, output, slider, thumb, track };
19
+
20
+ //# sourceMappingURL=Slider.module.js.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"Slider.module.js","names":[],"sources":["../../src/slider/Slider.module.css"],"sourcesContent":["/* A track with the part before the thumb filled, and the value next to the label. */\n\n.slider {\n width: 100%;\n}\n\n.header {\n display: flex;\n align-items: baseline;\n justify-content: space-between;\n gap: var(--panneau-space-2);\n}\n\n.output {\n font-size: var(--panneau-font-size-sm);\n font-variant-numeric: var(--panneau-font-numeric);\n color: var(--panneau-color-text-muted);\n}\n\n.track {\n position: relative;\n height: var(--panneau-control-height-sm);\n cursor: pointer;\n}\n\n/* The rail, centered in the track. */\n.track::before {\n position: absolute;\n top: 50%;\n right: 0;\n left: 0;\n height: 0.25rem;\n content: '';\n background-color: var(--panneau-color-surface-sunken);\n border: var(--panneau-border-width) solid var(--panneau-color-border);\n border-radius: var(--panneau-radius-full);\n transform: translateY(-50%);\n}\n\n.fill {\n position: absolute;\n top: 50%;\n left: 0;\n height: 0.25rem;\n background-color: var(--panneau-color-accent);\n border-radius: var(--panneau-radius-full);\n transform: translateY(-50%);\n}\n\n.thumb {\n top: 50%;\n width: 1.125rem;\n height: 1.125rem;\n background-color: var(--panneau-color-surface);\n border: 2px solid var(--panneau-color-accent);\n border-radius: var(--panneau-radius-full);\n box-shadow: var(--panneau-shadow-sm);\n transform: translateY(-50%);\n}\n\n.slider[data-empty] .thumb {\n border-color: var(--panneau-color-border-control);\n}\n\n.thumb[data-dragging] {\n background-color: var(--panneau-color-accent);\n}\n\n.thumb[data-focus-visible] {\n outline: var(--panneau-focus-width) solid var(--panneau-color-focus);\n outline-offset: 2px;\n}\n\n.slider[data-invalid] .thumb {\n border-color: var(--panneau-color-danger);\n}\n\n.slider[data-disabled] {\n opacity: 0.6;\n}\n\n.slider[data-disabled] .track {\n cursor: not-allowed;\n}\n"],"mappings":""}
@@ -0,0 +1,60 @@
1
+ /* The tags as chips in the control, before the input. */
2
+
3
+ .panneau-tags-input-control.panneau-tags-input-control {
4
+ flex-wrap: wrap;
5
+ gap: var(--panneau-space-1);
6
+ height: auto;
7
+ padding-block: var(--panneau-space-1);
8
+ }
9
+
10
+ .panneau-tags-input-group {
11
+ display: contents;
12
+ }
13
+
14
+ .panneau-tags-input-list {
15
+ display: contents;
16
+ }
17
+
18
+ .panneau-tags-input-tag {
19
+ display: inline-flex;
20
+ align-items: center;
21
+ gap: var(--panneau-space-1);
22
+ max-width: 100%;
23
+ padding: 0.125rem var(--panneau-space-1) 0.125rem var(--panneau-space-2);
24
+ font-size: var(--panneau-font-size-sm);
25
+ line-height: var(--panneau-line-height-tight);
26
+ color: var(--panneau-color-text);
27
+ background-color: var(--panneau-color-surface-sunken);
28
+ border: var(--panneau-border-width) solid var(--panneau-color-border);
29
+ border-radius: var(--panneau-radius-full);
30
+ outline: none;
31
+ overflow-wrap: anywhere;
32
+ }
33
+
34
+ .panneau-tags-input-tag[data-focus-visible] {
35
+ outline: var(--panneau-focus-width) solid var(--panneau-color-focus);
36
+ outline-offset: 1px;
37
+ }
38
+
39
+ .panneau-tags-input-remove {
40
+ display: inline-flex;
41
+ align-items: center;
42
+ justify-content: center;
43
+ padding: 0.125rem;
44
+ color: var(--panneau-color-text-muted);
45
+ cursor: pointer;
46
+ background: none;
47
+ border: 0;
48
+ border-radius: var(--panneau-radius-full);
49
+ outline: none;
50
+ }
51
+
52
+ .panneau-tags-input-remove[data-hovered] {
53
+ color: var(--panneau-color-text);
54
+ background-color: var(--panneau-color-hover);
55
+ }
56
+
57
+ .panneau-tags-input-input {
58
+ flex: 1 1 6rem;
59
+ min-width: 6rem;
60
+ }
@@ -0,0 +1,32 @@
1
+ import { type FieldChromeProps } from '../field/FieldParts';
2
+ /** A suggested tag: its value, and the label shown for it. */
3
+ export interface TagSuggestion {
4
+ value: string;
5
+ label?: string;
6
+ }
7
+ export interface TagsInputProps extends FieldChromeProps {
8
+ /** The tags, or `null` when there are none. */
9
+ value?: readonly string[] | null;
10
+ /** Called with the tags, or `null` when the last one is removed. */
11
+ onChange?: (value: string[] | null) => void;
12
+ onBlur?: () => void;
13
+ /** Tags offered as the user types. */
14
+ suggestions?: readonly TagSuggestion[];
15
+ /** Whether tags outside the suggestions are allowed. Defaults to true. */
16
+ allowCustom?: boolean;
17
+ placeholder?: string;
18
+ name?: string;
19
+ isRequired?: boolean;
20
+ isDisabled?: boolean;
21
+ isReadOnly?: boolean;
22
+ autoFocus?: boolean;
23
+ controlClassName?: string;
24
+ }
25
+ /**
26
+ * A list of words. Enter, Tab or a comma adds what is typed, Backspace in the empty input removes
27
+ * the last tag, and pasting a list separated by commas or lines adds each one. Tags are trimmed,
28
+ * and a tag already in the list isn't added again. Suggestions complete what is typed; without
29
+ * `allowCustom`, only they can be added.
30
+ */
31
+ export declare function TagsInput({ label, description, errors, value, onChange, onBlur, suggestions, allowCustom, placeholder, name, isRequired, isDisabled, isReadOnly, autoFocus, className, labelClassName, descriptionClassName, errorsClassName, controlClassName, }: TagsInputProps): import("react").JSX.Element;
32
+ //# sourceMappingURL=TagsInput.d.ts.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"TagsInput.d.ts","sourceRoot":"","sources":["../../src/tags-input/TagsInput.tsx"],"names":[],"mappings":"AAIA,OAAO,EAAE,KAAK,gBAAgB,EAAe,MAAM,qBAAqB,CAAC;AAOzE,8DAA8D;AAC9D,MAAM,WAAW,aAAa;IAC1B,KAAK,EAAE,MAAM,CAAC;IACd,KAAK,CAAC,EAAE,MAAM,CAAC;CAClB;AAED,MAAM,WAAW,cAAe,SAAQ,gBAAgB;IACpD,+CAA+C;IAC/C,KAAK,CAAC,EAAE,SAAS,MAAM,EAAE,GAAG,IAAI,CAAC;IACjC,oEAAoE;IACpE,QAAQ,CAAC,EAAE,CAAC,KAAK,EAAE,MAAM,EAAE,GAAG,IAAI,KAAK,IAAI,CAAC;IAC5C,MAAM,CAAC,EAAE,MAAM,IAAI,CAAC;IACpB,sCAAsC;IACtC,WAAW,CAAC,EAAE,SAAS,aAAa,EAAE,CAAC;IACvC,0EAA0E;IAC1E,WAAW,CAAC,EAAE,OAAO,CAAC;IACtB,WAAW,CAAC,EAAE,MAAM,CAAC;IACrB,IAAI,CAAC,EAAE,MAAM,CAAC;IACd,UAAU,CAAC,EAAE,OAAO,CAAC;IACrB,UAAU,CAAC,EAAE,OAAO,CAAC;IACrB,UAAU,CAAC,EAAE,OAAO,CAAC;IACrB,SAAS,CAAC,EAAE,OAAO,CAAC;IACpB,gBAAgB,CAAC,EAAE,MAAM,CAAC;CAC7B;AAED;;;;;GAKG;AACH,wBAAgB,SAAS,CAAC,EACtB,KAAK,EACL,WAAW,EACX,MAAW,EACX,KAAK,EACL,QAAQ,EACR,MAAM,EACN,WAAgB,EAChB,WAAkB,EAClB,WAAW,EACX,IAAI,EACJ,UAAU,EACV,UAAU,EACV,UAAU,EACV,SAAS,EACT,SAAS,EACT,cAAc,EACd,oBAAoB,EACpB,eAAe,EACf,gBAAgB,GACnB,EAAE,cAAc,+BAyLhB"}
@@ -0,0 +1,160 @@
1
+ import { cx } from "../utils/cx.js";
2
+ import { Icon } from "../icon/Icon.js";
3
+ import { messages } from "../intl/messages.js";
4
+ import { usePanneauIntl } from "../intl/usePanneauIntl.js";
5
+ import Field_module_default from "../field/Field.module.js";
6
+ import TagsInput_module_default from "./TagsInput.module.js";
7
+ import { X } from "lucide-react";
8
+ import { Button, Tag, TagGroup, TagList } from "react-aria-components";
9
+ import { jsx, jsxs } from "react/jsx-runtime";
10
+ import { useId, useState } from "react";
11
+ //#region src/tags-input/TagsInput.tsx
12
+ /**
13
+ * A list of words. Enter, Tab or a comma adds what is typed, Backspace in the empty input removes
14
+ * the last tag, and pasting a list separated by commas or lines adds each one. Tags are trimmed,
15
+ * and a tag already in the list isn't added again. Suggestions complete what is typed; without
16
+ * `allowCustom`, only they can be added.
17
+ */
18
+ function TagsInput({ label, description, errors = [], value, onChange, onBlur, suggestions = [], allowCustom = true, placeholder, name, isRequired, isDisabled, isReadOnly, autoFocus, className, labelClassName, descriptionClassName, errorsClassName, controlClassName }) {
19
+ const intl = usePanneauIntl();
20
+ const id = useId();
21
+ const [draft, setDraft] = useState("");
22
+ const tags = value ?? [];
23
+ const invalid = errors.length > 0;
24
+ const editable = isDisabled !== true && isReadOnly !== true;
25
+ const labelOf = (tag) => suggestions.find((suggestion) => suggestion.value === tag)?.label ?? tag;
26
+ /** The tag a text adds: the suggestion it names, or the text itself when allowed. */
27
+ const resolve = (text) => {
28
+ const trimmed = text.trim();
29
+ if (trimmed === "") return null;
30
+ const lower = trimmed.toLocaleLowerCase();
31
+ const suggestion_0 = suggestions.find((candidate) => candidate.value.toLocaleLowerCase() === lower || (candidate.label ?? "").toLocaleLowerCase() === lower);
32
+ if (suggestion_0 !== void 0) return suggestion_0.value;
33
+ return allowCustom ? trimmed : null;
34
+ };
35
+ const add = (texts) => {
36
+ const next = [...tags];
37
+ texts.forEach((text_0) => {
38
+ const tag_0 = resolve(text_0);
39
+ if (tag_0 !== null && !next.includes(tag_0)) next.push(tag_0);
40
+ });
41
+ if (next.length !== tags.length) onChange?.(next);
42
+ };
43
+ const remove = (removed) => {
44
+ const next_0 = tags.filter((tag_1) => !removed.has(tag_1));
45
+ onChange?.(next_0.length > 0 ? next_0 : null);
46
+ };
47
+ const commit = () => {
48
+ if (draft.trim() !== "") {
49
+ add([draft]);
50
+ setDraft("");
51
+ }
52
+ };
53
+ const onKeyDown = (event) => {
54
+ if (event.key === "Enter" || event.key === "," || event.key === "Tab" && draft !== "") {
55
+ if (draft.trim() !== "") {
56
+ event.preventDefault();
57
+ commit();
58
+ } else if (event.key !== "Tab") event.preventDefault();
59
+ } else if (event.key === "Backspace" && draft === "" && tags.length > 0) {
60
+ event.preventDefault();
61
+ remove(/* @__PURE__ */ new Set([tags[tags.length - 1]]));
62
+ }
63
+ };
64
+ const onPaste = (event_0) => {
65
+ const text_1 = event_0.clipboardData.getData("text");
66
+ if (/[,\n]/.test(text_1)) {
67
+ event_0.preventDefault();
68
+ add(text_1.split(/[,\n]/));
69
+ }
70
+ };
71
+ const describedBy = [description !== void 0 && description !== null ? `${id}-description` : null, invalid ? `${id}-errors` : null].filter((part) => part !== null).join(" ");
72
+ return /* @__PURE__ */ jsxs("div", {
73
+ className: cx("panneau-tags-input", Field_module_default.field, className),
74
+ children: [
75
+ label !== void 0 && label !== null ? /* @__PURE__ */ jsxs("label", {
76
+ htmlFor: `${id}-input`,
77
+ className: cx(Field_module_default.label, labelClassName),
78
+ children: [label, isRequired === true ? /* @__PURE__ */ jsx("span", {
79
+ className: Field_module_default.required,
80
+ "aria-hidden": "true",
81
+ children: "*"
82
+ }) : null]
83
+ }) : null,
84
+ /* @__PURE__ */ jsxs("div", {
85
+ className: cx(Field_module_default.control, TagsInput_module_default.control, controlClassName),
86
+ "data-invalid": invalid || void 0,
87
+ "data-disabled": isDisabled || void 0,
88
+ "data-readonly": isReadOnly || void 0,
89
+ children: [
90
+ tags.length > 0 ? /* @__PURE__ */ jsx(TagGroup, {
91
+ "aria-label": intl.formatMessage(messages.tags, { label: typeof label === "string" ? label : "" }),
92
+ onRemove: editable ? remove : void 0,
93
+ className: TagsInput_module_default.group,
94
+ children: /* @__PURE__ */ jsx(TagList, {
95
+ className: TagsInput_module_default.list,
96
+ children: tags.map((tag_2) => /* @__PURE__ */ jsxs(Tag, {
97
+ id: tag_2,
98
+ textValue: labelOf(tag_2),
99
+ className: TagsInput_module_default.tag,
100
+ children: [labelOf(tag_2), editable ? /* @__PURE__ */ jsx(Button, {
101
+ slot: "remove",
102
+ className: TagsInput_module_default.remove,
103
+ children: /* @__PURE__ */ jsx(Icon, {
104
+ icon: X,
105
+ size: "xs"
106
+ })
107
+ }) : null]
108
+ }, tag_2))
109
+ })
110
+ }) : null,
111
+ editable ? /* @__PURE__ */ jsx("input", {
112
+ id: `${id}-input`,
113
+ className: cx(Field_module_default.bare, TagsInput_module_default.input),
114
+ value: draft,
115
+ placeholder: tags.length === 0 ? placeholder : void 0,
116
+ list: suggestions.length > 0 ? `${id}-suggestions` : void 0,
117
+ autoComplete: "off",
118
+ autoFocus,
119
+ "aria-invalid": invalid || void 0,
120
+ "aria-required": isRequired || void 0,
121
+ "aria-describedby": describedBy !== "" ? describedBy : void 0,
122
+ onChange: (event_1) => setDraft(event_1.target.value),
123
+ onKeyDown,
124
+ onPaste,
125
+ onBlur: () => {
126
+ commit();
127
+ onBlur?.();
128
+ }
129
+ }) : null,
130
+ suggestions.length > 0 ? /* @__PURE__ */ jsx("datalist", {
131
+ id: `${id}-suggestions`,
132
+ children: suggestions.filter((suggestion_1) => !tags.includes(suggestion_1.value)).map((suggestion_2) => /* @__PURE__ */ jsx("option", { value: suggestion_2.label ?? suggestion_2.value }, suggestion_2.value))
133
+ }) : null
134
+ ]
135
+ }),
136
+ name !== void 0 ? tags.map((tag_3) => /* @__PURE__ */ jsx("input", {
137
+ type: "hidden",
138
+ name: `${name}[]`,
139
+ value: tag_3
140
+ }, tag_3)) : null,
141
+ description !== void 0 && description !== null ? /* @__PURE__ */ jsx("div", {
142
+ id: `${id}-description`,
143
+ className: cx(Field_module_default.description, descriptionClassName),
144
+ children: description
145
+ }) : null,
146
+ invalid ? /* @__PURE__ */ jsx("div", {
147
+ id: `${id}-errors`,
148
+ className: cx(Field_module_default.errors, errorsClassName),
149
+ children: errors.map((error, index) => /* @__PURE__ */ jsx("span", {
150
+ className: Field_module_default.error,
151
+ children: error
152
+ }, index))
153
+ }) : null
154
+ ]
155
+ });
156
+ }
157
+ //#endregion
158
+ export { TagsInput };
159
+
160
+ //# sourceMappingURL=TagsInput.js.map