@panneau/ui 5.0.0-alpha.5 → 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 (63) hide show
  1. package/README.md +54 -1
  2. package/dist/index.d.ts +5 -2
  3. package/dist/index.d.ts.map +1 -1
  4. package/dist/index.js +5 -2
  5. package/dist/menu/Menu.css +84 -0
  6. package/dist/menu/Menu.d.ts +33 -6
  7. package/dist/menu/Menu.d.ts.map +1 -1
  8. package/dist/menu/Menu.js +110 -25
  9. package/dist/menu/Menu.js.map +1 -1
  10. package/dist/menu/Menu.module.js +22 -0
  11. package/dist/menu/Menu.module.js.map +1 -0
  12. package/dist/menu/tokens.d.ts +3 -0
  13. package/dist/menu/tokens.d.ts.map +1 -0
  14. package/dist/menu/tokens.js +31 -0
  15. package/dist/menu/tokens.js.map +1 -0
  16. package/dist/number-input/NumberInput.css +18 -0
  17. package/dist/number-input/NumberInput.js +1 -1
  18. package/dist/number-input/NumberInput.js.map +1 -1
  19. package/dist/number-input/NumberInput.module.js +3 -1
  20. package/dist/number-input/NumberInput.module.js.map +1 -1
  21. package/dist/pill-trigger/PillTrigger.css +104 -0
  22. package/dist/pill-trigger/PillTrigger.d.ts +20 -0
  23. package/dist/pill-trigger/PillTrigger.d.ts.map +1 -0
  24. package/dist/pill-trigger/PillTrigger.js +38 -0
  25. package/dist/pill-trigger/PillTrigger.js.map +1 -0
  26. package/dist/pill-trigger/PillTrigger.module.js +18 -0
  27. package/dist/pill-trigger/PillTrigger.module.js.map +1 -0
  28. package/dist/pill-trigger/tokens.d.ts +3 -0
  29. package/dist/pill-trigger/tokens.d.ts.map +1 -0
  30. package/dist/pill-trigger/tokens.js +37 -0
  31. package/dist/pill-trigger/tokens.js.map +1 -0
  32. package/dist/radio-group/RadioGroup.css +90 -0
  33. package/dist/radio-group/RadioGroup.d.ts +22 -3
  34. package/dist/radio-group/RadioGroup.d.ts.map +1 -1
  35. package/dist/radio-group/RadioGroup.js +42 -21
  36. package/dist/radio-group/RadioGroup.js.map +1 -1
  37. package/dist/radio-group/RadioGroup.module.js +12 -2
  38. package/dist/radio-group/RadioGroup.module.js.map +1 -1
  39. package/dist/radio-group/tokens.d.ts +2 -2
  40. package/dist/radio-group/tokens.d.ts.map +1 -1
  41. package/dist/radio-group/tokens.js +22 -2
  42. package/dist/radio-group/tokens.js.map +1 -1
  43. package/dist/select/ListBox.css +15 -0
  44. package/dist/select/ListBox.module.js.map +1 -1
  45. package/dist/slider/Slider.css +84 -0
  46. package/dist/slider/Slider.d.ts +20 -0
  47. package/dist/slider/Slider.d.ts.map +1 -0
  48. package/dist/slider/Slider.js +70 -0
  49. package/dist/slider/Slider.js.map +1 -0
  50. package/dist/slider/Slider.module.js +20 -0
  51. package/dist/slider/Slider.module.js.map +1 -0
  52. package/dist/tags-input/TagsInput.css +60 -0
  53. package/dist/tags-input/TagsInput.d.ts +32 -0
  54. package/dist/tags-input/TagsInput.d.ts.map +1 -0
  55. package/dist/tags-input/TagsInput.js +160 -0
  56. package/dist/tags-input/TagsInput.js.map +1 -0
  57. package/dist/tags-input/TagsInput.module.js +20 -0
  58. package/dist/tags-input/TagsInput.module.js.map +1 -0
  59. package/dist/theme/components.d.ts +3 -1
  60. package/dist/theme/components.d.ts.map +1 -1
  61. package/dist/theme/components.js +4 -0
  62. package/dist/theme/components.js.map +1 -1
  63. package/package.json +3 -3
@@ -1 +1 @@
1
- {"version":3,"file":"RadioGroup.module.js","names":[],"sources":["../../src/radio-group/RadioGroup.module.css"],"sourcesContent":[".options {\n display: flex;\n flex-direction: column;\n gap: var(--panneau-space-1);\n}\n\n.horizontal .options {\n flex-flow: row wrap;\n gap: var(--panneau-space-1) var(--panneau-space-4);\n}\n\n.radio {\n display: inline-flex;\n align-items: flex-start;\n gap: var(--panneau-space-2);\n min-height: 1.5rem;\n font-size: var(--panneau-font-size-md);\n color: var(--panneau-color-text);\n cursor: pointer;\n -webkit-tap-highlight-color: transparent;\n}\n\n.radio[data-disabled] {\n cursor: not-allowed;\n opacity: 0.55;\n}\n\n.radio[data-readonly] {\n cursor: default;\n}\n\n.circle {\n flex: 0 0 auto;\n width: var(--panneau-radio-size, 1.125rem);\n height: var(--panneau-radio-size, 1.125rem);\n margin-top: 0.125rem;\n background-color: var(--panneau-radio-bg, var(--panneau-color-surface));\n border: var(--panneau-border-width) solid\n var(--panneau-radio-border-color, var(--panneau-color-border-control));\n border-radius: var(--panneau-radius-full);\n transition:\n border-color var(--panneau-duration),\n border-width var(--panneau-duration);\n}\n\n.radio[data-hovered] .circle {\n border-color: var(--panneau-color-text-muted);\n}\n\n.radio[data-selected] .circle {\n border-color: var(--panneau-radio-checked-color, var(--panneau-color-accent));\n border-width: var(--panneau-radio-checked-border-width, 0.3125rem);\n}\n\n.radio[data-invalid] .circle {\n border-color: var(--panneau-color-danger);\n}\n\n.radio[data-focus-visible] .circle {\n outline: var(--panneau-focus-width) solid var(--panneau-color-focus);\n outline-offset: 2px;\n}\n\n.text {\n display: flex;\n flex-direction: column;\n min-width: 0;\n}\n\n.description {\n font-size: var(--panneau-font-size-sm);\n color: var(--panneau-color-text-muted);\n}\n\n@media (pointer: coarse) {\n .radio {\n min-height: 2.75rem;\n align-items: center;\n }\n\n .circle {\n margin-top: 0;\n }\n}\n"],"mappings":""}
1
+ {"version":3,"file":"RadioGroup.module.js","names":[],"sources":["../../src/radio-group/RadioGroup.module.css"],"sourcesContent":[".options {\n display: flex;\n flex-direction: column;\n gap: var(--panneau-space-1);\n}\n\n.horizontal .options {\n flex-flow: row wrap;\n gap: var(--panneau-space-1) var(--panneau-space-4);\n}\n\n.radio {\n display: inline-flex;\n align-items: flex-start;\n gap: var(--panneau-space-2);\n min-height: 1.5rem;\n font-size: var(--panneau-font-size-md);\n color: var(--panneau-color-text);\n cursor: pointer;\n -webkit-tap-highlight-color: transparent;\n}\n\n.radio[data-disabled] {\n cursor: not-allowed;\n opacity: 0.55;\n}\n\n.radio[data-readonly] {\n cursor: default;\n}\n\n.circle {\n flex: 0 0 auto;\n width: var(--panneau-radio-size, 1.125rem);\n height: var(--panneau-radio-size, 1.125rem);\n margin-top: 0.125rem;\n background-color: var(--panneau-radio-bg, var(--panneau-color-surface));\n border: var(--panneau-border-width) solid\n var(--panneau-radio-border-color, var(--panneau-color-border-control));\n border-radius: var(--panneau-radius-full);\n transition:\n border-color var(--panneau-duration),\n border-width var(--panneau-duration);\n}\n\n.radio[data-hovered] .circle {\n border-color: var(--panneau-color-text-muted);\n}\n\n.radio[data-selected] .circle {\n border-color: var(--panneau-radio-checked-color, var(--panneau-color-accent));\n border-width: var(--panneau-radio-checked-border-width, 0.3125rem);\n}\n\n.radio[data-invalid] .circle {\n border-color: var(--panneau-color-danger);\n}\n\n.radio[data-focus-visible] .circle {\n outline: var(--panneau-focus-width) solid var(--panneau-color-focus);\n outline-offset: 2px;\n}\n\n.text {\n display: flex;\n flex-direction: column;\n min-width: 0;\n}\n\n.optionLabel {\n overflow-wrap: anywhere;\n}\n\n.description {\n font-size: var(--panneau-font-size-sm);\n color: var(--panneau-color-text-muted);\n}\n\n/* Leading media of an option, between the radio and the label. */\n.media {\n display: inline-flex;\n flex: 0 0 auto;\n align-items: center;\n justify-content: center;\n width: var(--panneau-radio-media-size, 2rem);\n height: var(--panneau-radio-media-size, 2rem);\n overflow: hidden;\n border-radius: var(--panneau-radio-media-radius, var(--panneau-radius-full));\n}\n\n.media > :is(img, svg, video, picture) {\n width: 100%;\n height: 100%;\n object-fit: cover;\n}\n\n/*\n * Cards: the options in a grid of --_panneau-radio-group-columns columns, inside a size container\n * of their own, so that they become a single column when the group is narrow, wherever it is.\n */\n\n.grid {\n container-type: inline-size;\n}\n\n.cards .options {\n display: grid;\n grid-template-columns: repeat(var(--_panneau-radio-group-columns, 2), minmax(0, 1fr));\n gap: var(--panneau-radio-card-gap, var(--panneau-space-2));\n}\n\n@container (max-width: 28rem) {\n .cards .options {\n grid-template-columns: minmax(0, 1fr);\n }\n}\n\n.card {\n display: flex;\n align-items: center;\n gap: var(--panneau-space-3);\n padding: var(--panneau-radio-card-padding, var(--panneau-space-3));\n background-color: var(--panneau-radio-card-bg, var(--panneau-color-surface));\n border: var(--panneau-border-width) solid\n var(--panneau-radio-card-border-color, var(--panneau-color-border));\n border-radius: var(--panneau-radio-card-radius, var(--panneau-radius-md));\n transition:\n border-color var(--panneau-duration),\n box-shadow var(--panneau-duration);\n}\n\n.card .circle {\n margin-top: 0;\n}\n\n.card .optionLabel {\n font-weight: var(--panneau-radio-card-label-font-weight, var(--panneau-font-weight-medium));\n}\n\n.card[data-hovered] {\n border-color: var(--panneau-radio-card-border-color-hover, var(--panneau-color-border-control));\n}\n\n/* The selected card: a border of twice the width, drawn inside so that nothing moves. */\n.card[data-selected] {\n border-color: var(--panneau-radio-card-border-color-selected, var(--panneau-color-accent));\n box-shadow: inset 0 0 0 var(--panneau-border-width)\n var(--panneau-radio-card-border-color-selected, var(--panneau-color-accent));\n}\n\n.card[data-invalid] {\n border-color: var(--panneau-color-danger);\n}\n\n/* A card shows the focus ring around itself, instead of around its radio. */\n.card[data-focus-visible] {\n outline: var(--panneau-focus-width) solid var(--panneau-color-focus);\n outline-offset: 2px;\n}\n\n.card[data-focus-visible] .circle {\n outline: none;\n}\n\n@media (pointer: coarse) {\n .radio {\n min-height: 2.75rem;\n align-items: center;\n }\n\n .circle {\n margin-top: 0;\n }\n}\n"],"mappings":""}
@@ -1,3 +1,3 @@
1
- /** Tokens of RadioGroup. */
2
- export declare const radioTokens: import("..").ComponentTokens<"radio", "panneau-radio-size" | "panneau-radio-bg" | "panneau-radio-border-color" | "panneau-radio-checked-color" | "panneau-radio-checked-border-width">;
1
+ /** Tokens of RadioGroup: its radios, the media of its options, and its cards. */
2
+ export declare const radioTokens: import("..").ComponentTokens<"radio", "panneau-radio-size" | "panneau-radio-bg" | "panneau-radio-border-color" | "panneau-radio-checked-color" | "panneau-radio-media-size" | "panneau-radio-media-radius" | "panneau-radio-checked-border-width" | "panneau-radio-card-gap" | "panneau-radio-card-padding" | "panneau-radio-card-bg" | "panneau-radio-card-border-color" | "panneau-radio-card-border-color-hover" | "panneau-radio-card-border-color-selected" | "panneau-radio-card-radius" | "panneau-radio-card-label-font-weight">;
3
3
  //# sourceMappingURL=tokens.d.ts.map
@@ -1 +1 @@
1
- {"version":3,"file":"tokens.d.ts","sourceRoot":"","sources":["../../src/radio-group/tokens.ts"],"names":[],"mappings":"AAEA,4BAA4B;AAC5B,eAAO,MAAM,WAAW,wLAWtB,CAAC"}
1
+ {"version":3,"file":"tokens.d.ts","sourceRoot":"","sources":["../../src/radio-group/tokens.ts"],"names":[],"mappings":"AAEA,iFAAiF;AACjF,eAAO,MAAM,WAAW,0gBA+BtB,CAAC"}
@@ -1,6 +1,6 @@
1
1
  import { defineComponentTokens } from "../theme/componentTokens.js";
2
2
  //#region src/radio-group/tokens.ts
3
- /** Tokens of RadioGroup. */
3
+ /** Tokens of RadioGroup: its radios, the media of its options, and its cards. */
4
4
  var radioTokens = defineComponentTokens("radio", {
5
5
  /** Size of the circle. */
6
6
  size: "1.125rem",
@@ -11,7 +11,27 @@ var radioTokens = defineComponentTokens("radio", {
11
11
  /** Color of a selected circle. */
12
12
  "checked-color": "var(--panneau-color-accent)",
13
13
  /** Border width of a selected circle, which draws the dot. */
14
- "checked-border-width": "0.3125rem"
14
+ "checked-border-width": "0.3125rem",
15
+ /** Size of the leading media of an option. */
16
+ "media-size": "2rem",
17
+ /** Corner radius of the leading media of an option: its content is clipped to it. */
18
+ "media-radius": "var(--panneau-radius-full)",
19
+ /** Space between the cards, with `appearance="cards"`. */
20
+ "card-gap": "var(--panneau-space-2)",
21
+ /** Padding of a card. */
22
+ "card-padding": "var(--panneau-space-3)",
23
+ /** Background of a card. */
24
+ "card-bg": "var(--panneau-color-surface)",
25
+ /** Border color of a card. */
26
+ "card-border-color": "var(--panneau-color-border)",
27
+ /** Border color of a hovered card. */
28
+ "card-border-color-hover": "var(--panneau-color-border-control)",
29
+ /** Border color of the selected card, which is twice as wide. */
30
+ "card-border-color-selected": "var(--panneau-color-accent)",
31
+ /** Corner radius of a card. */
32
+ "card-radius": "var(--panneau-radius-md)",
33
+ /** Font weight of the label of a card. */
34
+ "card-label-font-weight": "var(--panneau-font-weight-medium)"
15
35
  });
16
36
  //#endregion
17
37
  export { radioTokens };
@@ -1 +1 @@
1
- {"version":3,"file":"tokens.js","names":[],"sources":["../../src/radio-group/tokens.ts"],"sourcesContent":["import { defineComponentTokens } from '../theme/componentTokens';\n\n/** Tokens of RadioGroup. */\nexport const radioTokens = defineComponentTokens('radio', {\n /** Size of the circle. */\n size: '1.125rem',\n /** Background of the circle. */\n bg: 'var(--panneau-color-surface)',\n /** Border color of the circle. */\n 'border-color': 'var(--panneau-color-border-control)',\n /** Color of a selected circle. */\n 'checked-color': 'var(--panneau-color-accent)',\n /** Border width of a selected circle, which draws the dot. */\n 'checked-border-width': '0.3125rem',\n});\n"],"mappings":";;;AAGA,IAAa,cAAc,sBAAsB,SAAS;;CAEtD,MAAM;;CAEN,IAAI;;CAEJ,gBAAgB;;CAEhB,iBAAiB;;CAEjB,wBAAwB;AAC5B,CAAC"}
1
+ {"version":3,"file":"tokens.js","names":[],"sources":["../../src/radio-group/tokens.ts"],"sourcesContent":["import { defineComponentTokens } from '../theme/componentTokens';\n\n/** Tokens of RadioGroup: its radios, the media of its options, and its cards. */\nexport const radioTokens = defineComponentTokens('radio', {\n /** Size of the circle. */\n size: '1.125rem',\n /** Background of the circle. */\n bg: 'var(--panneau-color-surface)',\n /** Border color of the circle. */\n 'border-color': 'var(--panneau-color-border-control)',\n /** Color of a selected circle. */\n 'checked-color': 'var(--panneau-color-accent)',\n /** Border width of a selected circle, which draws the dot. */\n 'checked-border-width': '0.3125rem',\n /** Size of the leading media of an option. */\n 'media-size': '2rem',\n /** Corner radius of the leading media of an option: its content is clipped to it. */\n 'media-radius': 'var(--panneau-radius-full)',\n /** Space between the cards, with `appearance=\"cards\"`. */\n 'card-gap': 'var(--panneau-space-2)',\n /** Padding of a card. */\n 'card-padding': 'var(--panneau-space-3)',\n /** Background of a card. */\n 'card-bg': 'var(--panneau-color-surface)',\n /** Border color of a card. */\n 'card-border-color': 'var(--panneau-color-border)',\n /** Border color of a hovered card. */\n 'card-border-color-hover': 'var(--panneau-color-border-control)',\n /** Border color of the selected card, which is twice as wide. */\n 'card-border-color-selected': 'var(--panneau-color-accent)',\n /** Corner radius of a card. */\n 'card-radius': 'var(--panneau-radius-md)',\n /** Font weight of the label of a card. */\n 'card-label-font-weight': 'var(--panneau-font-weight-medium)',\n});\n"],"mappings":";;;AAGA,IAAa,cAAc,sBAAsB,SAAS;;CAEtD,MAAM;;CAEN,IAAI;;CAEJ,gBAAgB;;CAEhB,iBAAiB;;CAEjB,wBAAwB;;CAExB,cAAc;;CAEd,gBAAgB;;CAEhB,YAAY;;CAEZ,gBAAgB;;CAEhB,WAAW;;CAEX,qBAAqB;;CAErB,2BAA2B;;CAE3B,8BAA8B;;CAE9B,eAAe;;CAEf,0BAA0B;AAC9B,CAAC"}
@@ -103,6 +103,21 @@
103
103
  white-space: nowrap;
104
104
  }
105
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
+
106
121
  .panneau-list-box-value[data-placeholder] {
107
122
  color: var(--panneau-color-text-muted);
108
123
  }
@@ -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 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.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":""}
@@ -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
@@ -0,0 +1 @@
1
+ {"version":3,"file":"TagsInput.js","names":["suggestion","text","tag","next","event","fieldStyles","styles"],"sources":["../../src/tags-input/TagsInput.tsx"],"sourcesContent":["import { X } from 'lucide-react';\nimport { type ClipboardEvent, type KeyboardEvent, useId, useState } from 'react';\nimport { Button, Tag, TagGroup, TagList } from 'react-aria-components';\n\nimport { type FieldChromeProps, fieldStyles } from '../field/FieldParts';\nimport { Icon } from '../icon/Icon';\nimport { messages } from '../intl/messages';\nimport { usePanneauIntl } from '../intl/usePanneauIntl';\nimport { cx } from '../utils/cx';\nimport styles from './TagsInput.module.css';\n\n/** A suggested tag: its value, and the label shown for it. */\nexport interface TagSuggestion {\n value: string;\n label?: string;\n}\n\nexport interface TagsInputProps extends FieldChromeProps {\n /** The tags, or `null` when there are none. */\n value?: readonly string[] | null;\n /** Called with the tags, or `null` when the last one is removed. */\n onChange?: (value: string[] | null) => void;\n onBlur?: () => void;\n /** Tags offered as the user types. */\n suggestions?: readonly TagSuggestion[];\n /** Whether tags outside the suggestions are allowed. Defaults to true. */\n allowCustom?: boolean;\n placeholder?: string;\n name?: string;\n isRequired?: boolean;\n isDisabled?: boolean;\n isReadOnly?: boolean;\n autoFocus?: boolean;\n controlClassName?: string;\n}\n\n/**\n * A list of words. Enter, Tab or a comma adds what is typed, Backspace in the empty input removes\n * the last tag, and pasting a list separated by commas or lines adds each one. Tags are trimmed,\n * and a tag already in the list isn't added again. Suggestions complete what is typed; without\n * `allowCustom`, only they can be added.\n */\nexport function TagsInput({\n label,\n description,\n errors = [],\n value,\n onChange,\n onBlur,\n suggestions = [],\n allowCustom = true,\n placeholder,\n name,\n isRequired,\n isDisabled,\n isReadOnly,\n autoFocus,\n className,\n labelClassName,\n descriptionClassName,\n errorsClassName,\n controlClassName,\n}: TagsInputProps) {\n const intl = usePanneauIntl();\n const id = useId();\n const [draft, setDraft] = useState('');\n const tags = value ?? [];\n const invalid = errors.length > 0;\n const editable = isDisabled !== true && isReadOnly !== true;\n const labelOf = (tag: string) =>\n suggestions.find((suggestion) => suggestion.value === tag)?.label ?? tag;\n\n /** The tag a text adds: the suggestion it names, or the text itself when allowed. */\n const resolve = (text: string): string | null => {\n const trimmed = text.trim();\n if (trimmed === '') {\n return null;\n }\n const lower = trimmed.toLocaleLowerCase();\n const suggestion = suggestions.find(\n (candidate) =>\n candidate.value.toLocaleLowerCase() === lower ||\n (candidate.label ?? '').toLocaleLowerCase() === lower,\n );\n if (suggestion !== undefined) {\n return suggestion.value;\n }\n return allowCustom ? trimmed : null;\n };\n\n const add = (texts: readonly string[]) => {\n const next = [...tags];\n texts.forEach((text) => {\n const tag = resolve(text);\n if (tag !== null && !next.includes(tag)) {\n next.push(tag);\n }\n });\n if (next.length !== tags.length) {\n onChange?.(next);\n }\n };\n\n const remove = (removed: ReadonlySet<string | number>) => {\n const next = tags.filter((tag) => !removed.has(tag));\n onChange?.(next.length > 0 ? next : null);\n };\n\n const commit = () => {\n if (draft.trim() !== '') {\n add([draft]);\n setDraft('');\n }\n };\n\n const onKeyDown = (event: KeyboardEvent<HTMLInputElement>) => {\n if (event.key === 'Enter' || event.key === ',' || (event.key === 'Tab' && draft !== '')) {\n if (draft.trim() !== '') {\n event.preventDefault();\n commit();\n } else if (event.key !== 'Tab') {\n event.preventDefault();\n }\n } else if (event.key === 'Backspace' && draft === '' && tags.length > 0) {\n event.preventDefault();\n remove(new Set([tags[tags.length - 1] as string]));\n }\n };\n\n const onPaste = (event: ClipboardEvent<HTMLInputElement>) => {\n const text = event.clipboardData.getData('text');\n if (/[,\\n]/.test(text)) {\n event.preventDefault();\n add(text.split(/[,\\n]/));\n }\n };\n\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\n return (\n <div className={cx('panneau-tags-input', fieldStyles.field, className)}>\n {label !== undefined && label !== null ? (\n <label htmlFor={`${id}-input`} className={cx(fieldStyles.label, labelClassName)}>\n {label}\n {isRequired === true ? (\n <span className={fieldStyles.required} aria-hidden=\"true\">\n *\n </span>\n ) : null}\n </label>\n ) : null}\n <div\n className={cx(fieldStyles.control, styles.control, controlClassName)}\n data-invalid={invalid || undefined}\n data-disabled={isDisabled || undefined}\n data-readonly={isReadOnly || undefined}\n >\n {tags.length > 0 ? (\n <TagGroup\n aria-label={intl.formatMessage(messages.tags, {\n label: typeof label === 'string' ? label : '',\n })}\n onRemove={editable ? remove : undefined}\n className={styles.group}\n >\n <TagList className={styles.list}>\n {tags.map((tag) => (\n <Tag\n key={tag}\n id={tag}\n textValue={labelOf(tag)}\n className={styles.tag}\n >\n {labelOf(tag)}\n {editable ? (\n <Button slot=\"remove\" className={styles.remove}>\n <Icon icon={X} size=\"xs\" />\n </Button>\n ) : null}\n </Tag>\n ))}\n </TagList>\n </TagGroup>\n ) : null}\n {editable ? (\n <input\n id={`${id}-input`}\n className={cx(fieldStyles.bare, styles.input)}\n value={draft}\n placeholder={tags.length === 0 ? placeholder : undefined}\n list={suggestions.length > 0 ? `${id}-suggestions` : undefined}\n autoComplete=\"off\"\n autoFocus={autoFocus}\n aria-invalid={invalid || undefined}\n aria-required={isRequired || undefined}\n aria-describedby={describedBy !== '' ? describedBy : undefined}\n onChange={(event) => setDraft(event.target.value)}\n onKeyDown={onKeyDown}\n onPaste={onPaste}\n onBlur={() => {\n commit();\n onBlur?.();\n }}\n />\n ) : null}\n {suggestions.length > 0 ? (\n <datalist id={`${id}-suggestions`}>\n {suggestions\n .filter((suggestion) => !tags.includes(suggestion.value))\n .map((suggestion) => (\n <option\n key={suggestion.value}\n value={suggestion.label ?? suggestion.value}\n />\n ))}\n </datalist>\n ) : null}\n </div>\n {name !== undefined\n ? tags.map((tag) => (\n <input key={tag} type=\"hidden\" name={`${name}[]`} value={tag} />\n ))\n : null}\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 </div>\n );\n}\n"],"mappings":"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"}