@pathscale/ui 3.0.0 → 3.1.0

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 (52) hide show
  1. package/dist/components/auth-field-group/AuthFieldGroup.css +11 -3
  2. package/dist/components/button/Button.css +4 -4
  3. package/dist/components/card/Card.generated.d.ts +21 -2
  4. package/dist/components/card/index.d.ts +1 -1
  5. package/dist/components/checkbox/Checkbox.generated.d.ts +23 -2
  6. package/dist/components/checkbox/Checkbox.generated.js +14 -6
  7. package/dist/components/connection-settings/ConnectionSettings.css +76 -0
  8. package/dist/components/connection-settings/ConnectionSettings.generated.d.ts +45 -0
  9. package/dist/components/connection-settings/ConnectionSettings.generated.js +300 -0
  10. package/dist/components/connection-settings/ConnectionSettings.recipe.d.ts +54 -0
  11. package/dist/components/connection-settings/ConnectionSettings.recipe.js +111 -0
  12. package/dist/components/connection-settings/index.d.ts +2 -0
  13. package/dist/components/connection-settings/index.js +1 -0
  14. package/dist/components/dialog/Dialog.generated.js +17 -79
  15. package/dist/components/drawer/Drawer.a11y.d.ts +1 -3
  16. package/dist/components/drawer/Drawer.a11y.js +2 -30
  17. package/dist/components/drawer/Drawer.generated.js +17 -40
  18. package/dist/components/grid/Grid.generated.js +3 -3
  19. package/dist/components/input/Input.css +5 -3
  20. package/dist/components/input/Input.generated.js +6 -3
  21. package/dist/components/password-field/PasswordField.generated.d.ts +9 -1
  22. package/dist/components/password-field/PasswordField.generated.js +2 -2
  23. package/dist/components/password-field/PasswordField.interactions.d.ts +2 -2
  24. package/dist/components/password-field/PasswordField.interactions.js +2 -2
  25. package/dist/components/popover/Popover.generated.js +14 -11
  26. package/dist/components/radio/Radio.generated.d.ts +26 -2
  27. package/dist/components/radio/Radio.generated.js +9 -5
  28. package/dist/components/select/Select.generated.js +5 -0
  29. package/dist/components/slider/Slider.generated.d.ts +14 -1
  30. package/dist/components/slider/Slider.generated.js +3 -2
  31. package/dist/components/switch/Switch.css +0 -3
  32. package/dist/components/switch/Switch.generated.d.ts +23 -2
  33. package/dist/components/switch/Switch.generated.js +21 -44
  34. package/dist/components/switch/Switch.recipe.d.ts +61 -38
  35. package/dist/components/switch/Switch.recipe.js +88 -68
  36. package/dist/components/text/Text.generated.js +2 -6
  37. package/dist/components/text/Text.recipe.d.ts +17 -5
  38. package/dist/components/text/Text.recipe.js +7 -13
  39. package/dist/hooks/connection/createConnectionSettings.d.ts +128 -0
  40. package/dist/hooks/connection/createConnectionSettings.js +211 -0
  41. package/dist/hooks/connection/index.d.ts +2 -0
  42. package/dist/hooks/connection/index.js +1 -0
  43. package/dist/index.d.ts +5 -1
  44. package/dist/index.js +2 -0
  45. package/dist/layouts.manifest.json +1 -1
  46. package/dist/lib/focus.d.ts +31 -0
  47. package/dist/lib/focus.js +39 -0
  48. package/dist/lib/overlay.d.ts +94 -0
  49. package/dist/lib/overlay.js +72 -0
  50. package/dist/purge-manifest.json +14427 -15269
  51. package/dist/styles/base/index.css +42 -0
  52. package/package.json +3 -3
@@ -0,0 +1,111 @@
1
+ import { recipe } from "../../lib/layouts/index.js";
2
+ const componentRecipe = recipe({
3
+ component: "connection-settings",
4
+ element: "form",
5
+ slots: {
6
+ root: {
7
+ base: "connection-settings"
8
+ },
9
+ header: {
10
+ base: "connection-settings__header"
11
+ },
12
+ title: {
13
+ base: "connection-settings__title"
14
+ },
15
+ description: {
16
+ base: "connection-settings__description"
17
+ },
18
+ switch: {
19
+ base: "connection-settings__switch"
20
+ },
21
+ fields: {
22
+ base: "connection-settings__fields"
23
+ },
24
+ field: {
25
+ base: "connection-settings__field"
26
+ },
27
+ label: {
28
+ base: "connection-settings__label"
29
+ },
30
+ input: {
31
+ base: "connection-settings__input"
32
+ },
33
+ hint: {
34
+ base: "connection-settings__hint"
35
+ },
36
+ current: {
37
+ base: "connection-settings__current"
38
+ },
39
+ actions: {
40
+ base: "connection-settings__actions"
41
+ }
42
+ },
43
+ _layouts: {
44
+ slots: {
45
+ root: {
46
+ base: "connection-settings",
47
+ axes: {}
48
+ },
49
+ header: {
50
+ base: "connection-settings__header",
51
+ axes: {}
52
+ },
53
+ title: {
54
+ base: "connection-settings__title",
55
+ axes: {}
56
+ },
57
+ description: {
58
+ base: "connection-settings__description",
59
+ axes: {}
60
+ },
61
+ switch: {
62
+ base: "connection-settings__switch",
63
+ axes: {}
64
+ },
65
+ fields: {
66
+ base: "connection-settings__fields",
67
+ axes: {}
68
+ },
69
+ field: {
70
+ base: "connection-settings__field",
71
+ axes: {}
72
+ },
73
+ label: {
74
+ base: "connection-settings__label",
75
+ axes: {}
76
+ },
77
+ input: {
78
+ base: "connection-settings__input",
79
+ axes: {}
80
+ },
81
+ hint: {
82
+ base: "connection-settings__hint",
83
+ axes: {}
84
+ },
85
+ current: {
86
+ base: "connection-settings__current",
87
+ axes: {}
88
+ },
89
+ actions: {
90
+ base: "connection-settings__actions",
91
+ axes: {}
92
+ }
93
+ },
94
+ stateKeys: [],
95
+ slotIds: {
96
+ root: 9,
97
+ header: 5,
98
+ title: 11,
99
+ description: 2,
100
+ switch: 10,
101
+ fields: 4,
102
+ field: 3,
103
+ label: 8,
104
+ input: 7,
105
+ hint: 6,
106
+ current: 1,
107
+ actions: 0
108
+ }
109
+ }
110
+ });
111
+ export { componentRecipe };
@@ -0,0 +1,2 @@
1
+ export type { ConnectionSettingsEndpointLabel, ConnectionSettingsLabels, ConnectionSettingsProps, } from "./ConnectionSettings.generated";
2
+ export { ConnectionSettingsLayout as default, ConnectionSettingsLayout as ConnectionSettings, } from "./ConnectionSettings.generated";
@@ -0,0 +1 @@
1
+ export { ConnectionSettingsLayout as ConnectionSettings, ConnectionSettingsLayout as default } from "./ConnectionSettings.generated.js";
@@ -3,6 +3,8 @@ import { defineComponent } from "solid-layouts/solid-2/application-boundary";
3
3
  import "./Dialog.css";
4
4
  import { Show, createContext, createSignal, createTrackedEffect, createUniqueId, omit, onCleanup, useContext } from "solid-js";
5
5
  import { twMerge } from "../../lib/twMerge.js";
6
+ import { focusFirst } from "../../lib/focus.js";
7
+ import { lockBodyScroll, registerOverlay } from "../../lib/overlay.js";
6
8
  import "../_shared/material.css";
7
9
  import { CLASSES, componentRecipe } from "./Dialog.recipe.js";
8
10
  var _tmpl$ = /*#__PURE__*/ template("<div>"), _tmpl$2 = /*#__PURE__*/ template("<button>"), _tmpl$3 = /*#__PURE__*/ template("<div><div>"), _tmpl$4 = /*#__PURE__*/ template("<h2>"), _tmpl$5 = /*#__PURE__*/ template('<svg><path d="M18 6L6 18M6 6L18 18"stroke=currentColor stroke-width=2 stroke-linecap=round stroke-linejoin=round>');
@@ -13,61 +15,7 @@ const useModalContext = ()=>{
13
15
  return context;
14
16
  };
15
17
  const isVisibleState = (state)=>"entering" === state || "open" === state;
16
- let bodyLockCount = 0;
17
- let previousBodyOverflow = "";
18
- let previousBodyPaddingRight = "";
19
- const lockBodyScroll = ()=>{
20
- if (0 === bodyLockCount) {
21
- previousBodyOverflow = document.body.style.overflow;
22
- previousBodyPaddingRight = document.body.style.paddingRight;
23
- const scrollbarWidth = window.innerWidth - document.documentElement.clientWidth;
24
- if (scrollbarWidth > 0) document.body.style.paddingRight = `${scrollbarWidth}px`;
25
- document.body.style.overflow = "hidden";
26
- }
27
- bodyLockCount += 1;
28
- };
29
- const unlockBodyScroll = ()=>{
30
- if (bodyLockCount <= 0) return;
31
- bodyLockCount -= 1;
32
- if (0 === bodyLockCount) {
33
- document.body.style.overflow = previousBodyOverflow;
34
- document.body.style.paddingRight = previousBodyPaddingRight;
35
- }
36
- };
37
- const FOCUSABLE_SELECTOR = "a[href],area[href],button:not([disabled]),input:not([disabled]):not([type='hidden']),select:not([disabled]),textarea:not([disabled]),iframe,object,embed,[contenteditable='true'],[tabindex]:not([tabindex='-1'])";
38
- const getFocusableElements = (container)=>Array.from(container.querySelectorAll(FOCUSABLE_SELECTOR)).filter((element)=>{
39
- if (element.hasAttribute("disabled")) return false;
40
- if ("true" === element.getAttribute("aria-hidden")) return false;
41
- if (element.tabIndex < 0) return false;
42
- return !element.hidden;
43
- });
44
- const trapFocus = (event, container)=>{
45
- const focusable = getFocusableElements(container);
46
- if (0 === focusable.length) {
47
- event.preventDefault();
48
- container.focus();
49
- return;
50
- }
51
- const first = focusable[0];
52
- const last = focusable[focusable.length - 1];
53
- const active = document.activeElement;
54
- if (!event.shiftKey && active === last) {
55
- event.preventDefault();
56
- first.focus();
57
- return;
58
- }
59
- if (event.shiftKey && (active === first || active === container)) {
60
- event.preventDefault();
61
- last.focus();
62
- }
63
- };
64
- const focusFirstElement = (container)=>{
65
- const autofocus = container.querySelector("[autofocus]");
66
- if (autofocus) return void autofocus.focus();
67
- const focusable = getFocusableElements(container);
68
- if (focusable.length > 0) return void focusable[0].focus();
69
- container.focus();
70
- };
18
+ const focusFirstElement = focusFirst;
71
19
  const __solidLayoutDialogRoot = (_stable, p)=>{
72
20
  const others = omit(p, "children", "class", "dataTheme", "style", "ref", "open", "defaultOpen", "onOpenChange", "isDismissable", "shouldCloseOnEsc", "shouldCloseOnBackdropClick", "placement", "size", "backdrop", "scrollBehavior");
73
21
  const [internalOpen, setInternalOpen] = createSignal(Boolean(p.defaultOpen));
@@ -107,22 +55,18 @@ const __solidLayoutDialogRoot = (_stable, p)=>{
107
55
  onCleanup(()=>{
108
56
  if (exitTimer) clearTimeout(exitTimer);
109
57
  });
110
- let hasScrollLock = false;
58
+ let releaseScrollLock;
111
59
  createTrackedEffect(()=>{
112
60
  const shouldLock = isVisibleState(animState());
113
- if (shouldLock && !hasScrollLock) {
114
- lockBodyScroll();
115
- hasScrollLock = true;
116
- } else if (!shouldLock && hasScrollLock) {
117
- unlockBodyScroll();
118
- hasScrollLock = false;
61
+ if (shouldLock && !releaseScrollLock) releaseScrollLock = lockBodyScroll();
62
+ else if (!shouldLock && releaseScrollLock) {
63
+ releaseScrollLock();
64
+ releaseScrollLock = void 0;
119
65
  }
120
66
  });
121
67
  onCleanup(()=>{
122
- if (hasScrollLock) {
123
- unlockBodyScroll();
124
- hasScrollLock = false;
125
- }
68
+ releaseScrollLock?.();
69
+ releaseScrollLock = void 0;
126
70
  });
127
71
  let restoreFocusTarget = null;
128
72
  createTrackedEffect(()=>{
@@ -134,20 +78,14 @@ const __solidLayoutDialogRoot = (_stable, p)=>{
134
78
  queueMicrotask(()=>{
135
79
  if (!content.contains(document.activeElement)) focusFirstElement(content);
136
80
  });
137
- const handleDocumentKeyDown = (event)=>{
138
- if (!isVisibleState(animState())) return;
139
- if ("Escape" === event.key) {
140
- if (false !== p.isDismissable && false !== p.shouldCloseOnEsc) {
141
- event.preventDefault();
142
- setIsOpen(false);
143
- }
144
- return;
145
- }
146
- if ("Tab" === event.key) trapFocus(event, content);
147
- };
148
- document.addEventListener("keydown", handleDocumentKeyDown);
81
+ const releaseOverlay = registerOverlay({
82
+ dismissable: ()=>false !== p.isDismissable && false !== p.shouldCloseOnEsc,
83
+ dismiss: ()=>setIsOpen(false),
84
+ element: ()=>contentRef() ?? void 0,
85
+ modal: true
86
+ });
149
87
  return ()=>{
150
- document.removeEventListener("keydown", handleDocumentKeyDown);
88
+ releaseOverlay();
151
89
  };
152
90
  });
153
91
  createTrackedEffect(()=>{
@@ -6,6 +6,4 @@ export type DrawerAnimState = "entering" | "open" | "exiting" | "closed";
6
6
  export type DrawerCloseReason = "escape" | "backdrop" | "trigger" | "api";
7
7
  export declare const isSidePlacement: (placement: DrawerPlacement) => placement is "left" | "right";
8
8
  export declare const isVisibleState: (state: DrawerAnimState) => state is "open" | "entering";
9
- export declare const getFocusable: (container: HTMLElement) => HTMLElement[];
10
- export declare const focusFirst: (container: HTMLElement) => void;
11
- export declare const trapFocus: (event: KeyboardEvent, container: HTMLElement) => void;
9
+ export { focusFirst, getFocusable, trapFocus } from "../../lib/focus";
@@ -1,32 +1,4 @@
1
1
  const isSidePlacement = (placement)=>"left" === placement || "right" === placement;
2
2
  const isVisibleState = (state)=>"entering" === state || "open" === state;
3
- const FOCUSABLE_SELECTOR = "a[href],area[href],button:not([disabled]),input:not([disabled]):not([type='hidden']),select:not([disabled]),textarea:not([disabled]),[contenteditable='true'],[tabindex]:not([tabindex='-1'])";
4
- const getFocusable = (container)=>Array.from(container.querySelectorAll(FOCUSABLE_SELECTOR)).filter((el)=>!el.hidden && el.tabIndex >= 0 && "true" !== el.getAttribute("aria-hidden"));
5
- const focusFirst = (container)=>{
6
- const autofocus = container.querySelector("[autofocus]");
7
- if (autofocus) return void autofocus.focus();
8
- const nodes = getFocusable(container);
9
- if (nodes.length > 0) return void nodes[0].focus();
10
- container.focus();
11
- };
12
- const trapFocus = (event, container)=>{
13
- const nodes = getFocusable(container);
14
- if (0 === nodes.length) {
15
- event.preventDefault();
16
- container.focus();
17
- return;
18
- }
19
- const first = nodes[0];
20
- const last = nodes[nodes.length - 1];
21
- const active = document.activeElement;
22
- if (!event.shiftKey && active === last) {
23
- event.preventDefault();
24
- first.focus();
25
- return;
26
- }
27
- if (event.shiftKey && (active === first || active === container)) {
28
- event.preventDefault();
29
- last.focus();
30
- }
31
- };
32
- export { focusFirst, getFocusable, isSidePlacement, isVisibleState, trapFocus };
3
+ export { focusFirst, getFocusable, trapFocus } from "../../lib/focus.js";
4
+ export { isSidePlacement, isVisibleState };
@@ -3,32 +3,12 @@ import { defineComponent } from "solid-layouts/solid-2/application-boundary";
3
3
  import "./Drawer.css";
4
4
  import { Show, createSignal, createTrackedEffect, createUniqueId, omit, onCleanup } from "solid-js";
5
5
  import { twMerge } from "../../lib/twMerge.js";
6
+ import { lockBodyScroll, registerOverlay } from "../../lib/overlay.js";
6
7
  import "../_shared/material.css";
7
- import { focusFirst, isSidePlacement, isVisibleState, trapFocus } from "./Drawer.a11y.js";
8
+ import { focusFirst, isSidePlacement, isVisibleState } from "./Drawer.a11y.js";
8
9
  import { CLASSES, componentRecipe } from "./Drawer.recipe.js";
9
10
  import { DrawerContext, useDrawerContext } from "./Drawer.context.js";
10
11
  var _tmpl$ = /*#__PURE__*/ template("<div>"), _tmpl$2 = /*#__PURE__*/ template("<button>"), _tmpl$3 = /*#__PURE__*/ template("<h2>"), _tmpl$4 = /*#__PURE__*/ template("<div><div data-slot=drawer-handle-bar>"), _tmpl$5 = /*#__PURE__*/ template("<button><!><!><!>"), _tmpl$6 = /*#__PURE__*/ template("<span>"), _tmpl$7 = /*#__PURE__*/ template("<span data-slot=drawer-close>");
11
- let bodyLockCount = 0;
12
- let prevBodyOverflow = "";
13
- let prevBodyPaddingRight = "";
14
- const lockBodyScroll = ()=>{
15
- if (0 === bodyLockCount) {
16
- prevBodyOverflow = document.body.style.overflow;
17
- prevBodyPaddingRight = document.body.style.paddingRight;
18
- const scrollbarWidth = window.innerWidth - document.documentElement.clientWidth;
19
- if (scrollbarWidth > 0) document.body.style.paddingRight = `${scrollbarWidth}px`;
20
- document.body.style.overflow = "hidden";
21
- }
22
- bodyLockCount += 1;
23
- };
24
- const unlockBodyScroll = ()=>{
25
- if (bodyLockCount <= 0) return;
26
- bodyLockCount -= 1;
27
- if (0 === bodyLockCount) {
28
- document.body.style.overflow = prevBodyOverflow;
29
- document.body.style.paddingRight = prevBodyPaddingRight;
30
- }
31
- };
32
12
  const EXIT_MS = 200;
33
13
  const __solidLayoutDrawerRoot = (_stable, p)=>{
34
14
  const others = omit(p, "children", "class", "dataTheme", "style", "open", "defaultOpen", "onOpenChange", "placement", "size", "backdrop", "scrollBehavior", "isDismissable", "shouldCloseOnEsc", "shouldCloseOnBackdropClick", "trapFocus", "restoreFocus");
@@ -87,19 +67,18 @@ const __solidLayoutDrawerRoot = (_stable, p)=>{
87
67
  onCleanup(()=>{
88
68
  if (exitTimer) clearTimeout(exitTimer);
89
69
  });
90
- let hasScrollLock = false;
70
+ let releaseScrollLock;
91
71
  createTrackedEffect(()=>{
92
72
  const visible = isVisibleState(animState());
93
- if (visible && !hasScrollLock) {
94
- lockBodyScroll();
95
- hasScrollLock = true;
96
- } else if (!visible && hasScrollLock) {
97
- unlockBodyScroll();
98
- hasScrollLock = false;
73
+ if (visible && !releaseScrollLock) releaseScrollLock = lockBodyScroll();
74
+ else if (!visible && releaseScrollLock) {
75
+ releaseScrollLock();
76
+ releaseScrollLock = void 0;
99
77
  }
100
78
  });
101
79
  onCleanup(()=>{
102
- if (hasScrollLock) unlockBodyScroll();
80
+ releaseScrollLock?.();
81
+ releaseScrollLock = void 0;
103
82
  });
104
83
  let restoreFocusTarget = null;
105
84
  createTrackedEffect(()=>{
@@ -113,17 +92,15 @@ const __solidLayoutDrawerRoot = (_stable, p)=>{
113
92
  queueMicrotask(()=>{
114
93
  if (trapFocusEnabled() && !dialog.contains(document.activeElement)) focusFirst(dialog);
115
94
  });
116
- const onKeyDown = (event)=>{
117
- if (!isVisibleState(animState())) return;
118
- if ("Escape" === event.key) {
119
- event.preventDefault();
120
- requestClose("escape");
121
- return;
122
- }
123
- if ("Tab" === event.key && trapFocusEnabled()) trapFocus(event, dialog);
95
+ const releaseOverlay = registerOverlay({
96
+ dismissable: ()=>isDismissable() && shouldCloseOnEsc(),
97
+ dismiss: ()=>requestClose("escape"),
98
+ element: ()=>dialog,
99
+ modal: trapFocusEnabled()
100
+ });
101
+ return ()=>{
102
+ releaseOverlay();
124
103
  };
125
- document.addEventListener("keydown", onKeyDown);
126
- return ()=>document.removeEventListener("keydown", onKeyDown);
127
104
  });
128
105
  createTrackedEffect(()=>{
129
106
  if ("closed" !== animState() || !restoreFocusEnabled()) return;
@@ -1,7 +1,7 @@
1
1
  import { Dynamic, createComponent, mergeProps } from "@solidjs/web";
2
2
  import { defineComponent } from "solid-layouts/solid-2/application-boundary";
3
3
  import "./Grid.css";
4
- import { children, merge, omit } from "solid-js";
4
+ import { children, createMemo, merge, omit } from "solid-js";
5
5
  import { twMerge } from "../../lib/twMerge.js";
6
6
  import clsx from "clsx";
7
7
  import { mapResponsiveProp } from "../utils.js";
@@ -12,13 +12,13 @@ const __solidLayoutGrid = (_stable, p)=>{
12
12
  }, p);
13
13
  const rest = omit(merged, "as", "class", "children", "cols", "rows", "flow", "gap", "autoCols", "autoRows");
14
14
  const resolvedChildren = children(()=>merged.children);
15
- const classes = clsx(CLASSES.base, mapResponsiveProp(merged.cols, CLASSES.cols), mapResponsiveProp(merged.rows, CLASSES.rows), mapResponsiveProp(merged.flow, CLASSES.flow), mapResponsiveProp(merged.gap, CLASSES.gap), mapResponsiveProp(merged.autoCols, CLASSES.autoCols), mapResponsiveProp(merged.autoRows, CLASSES.autoRows), merged.class);
15
+ const classes = createMemo(()=>clsx(CLASSES.base, mapResponsiveProp(merged.cols, CLASSES.cols), mapResponsiveProp(merged.rows, CLASSES.rows), mapResponsiveProp(merged.flow, CLASSES.flow), mapResponsiveProp(merged.gap, CLASSES.gap), mapResponsiveProp(merged.autoCols, CLASSES.autoCols), mapResponsiveProp(merged.autoRows, CLASSES.autoRows), merged.class));
16
16
  return createComponent(Dynamic, mergeProps({
17
17
  get component () {
18
18
  return merged.as;
19
19
  }
20
20
  }, ()=>({
21
- class: twMerge(classes)
21
+ class: twMerge(classes())
22
22
  }), rest, {
23
23
  get children () {
24
24
  return resolvedChildren();
@@ -88,19 +88,21 @@
88
88
  }
89
89
 
90
90
  .input-control--sm {
91
- min-height: 2rem;
91
+ /* Was 2rem, which is 0.25rem shorter than `Button` at the same declared
92
+ size. Aligned to the shared scale so a button beside an input matches. */
93
+ min-height: var(--control-h-sm);
92
94
  padding-inline: 0.625rem;
93
95
  font-size: 0.75rem;
94
96
  }
95
97
 
96
98
  .input-control--md {
97
- min-height: 2.5rem;
99
+ min-height: var(--control-h-md);
98
100
  padding-inline: 0.75rem;
99
101
  font-size: 0.875rem;
100
102
  }
101
103
 
102
104
  .input-control--lg {
103
- min-height: 2.75rem;
105
+ min-height: var(--control-h-lg);
104
106
  padding-inline: 0.875rem;
105
107
  font-size: 1rem;
106
108
  }
@@ -10,7 +10,7 @@ const InputContext = createContext(null);
10
10
  const __solidLayoutInputRoot = (_stable, p)=>{
11
11
  const others = omit(p, "children", "class", "size", "fullWidth", "state", "issues", "dataTheme");
12
12
  const baseId = createUniqueId();
13
- const size = ()=>p.size ?? "md";
13
+ const size = ()=>p.size ?? "sm";
14
14
  const isDisabled = ()=>Boolean("disabled" === p.state);
15
15
  const isInvalid = ()=>Boolean("invalid" === resolveState(p.state, p.issues));
16
16
  const fullWidth = ()=>Boolean(p.fullWidth);
@@ -54,7 +54,7 @@ const InputRoot = defineComponent({
54
54
  const __solidLayoutInputField = (_stable, p)=>{
55
55
  const ctx = useContext(InputContext);
56
56
  const others = omit(p, "class", "size", "state", "disabled", "issues", "fullWidth", "startIcon", "endIcon", "dataTheme", "id", "aria-invalid");
57
- const size = ()=>p.size ?? ctx?.size() ?? "md";
57
+ const size = ()=>p.size ?? ctx?.size() ?? "sm";
58
58
  const isDisabled = ()=>Boolean("disabled" === p.state) || Boolean(p.disabled) || Boolean(ctx?.isDisabled());
59
59
  const isInvalid = ()=>Boolean("invalid" === resolveState(p.state, p.issues)) || Boolean(p["aria-invalid"]) || Boolean(ctx?.isInvalid());
60
60
  const fullWidth = ()=>Boolean(p.fullWidth) || Boolean(ctx?.fullWidth());
@@ -204,7 +204,7 @@ const __solidLayoutInputBase = (_stable, p)=>{
204
204
  return p.fullWidth ?? true;
205
205
  },
206
206
  get state () {
207
- return isDisabled() ? "disabled" : void 0;
207
+ return memo(()=>!!isDisabled())() ? "disabled" : isInvalid() ? "invalid" : void 0;
208
208
  },
209
209
  get issues () {
210
210
  return p.issues;
@@ -220,6 +220,9 @@ const __solidLayoutInputBase = (_stable, p)=>{
220
220
  },
221
221
  get children () {
222
222
  return createComponent(InputLabel, {
223
+ get ["for"] () {
224
+ return inputId();
225
+ },
223
226
  get children () {
224
227
  return p.label;
225
228
  }
@@ -18,7 +18,15 @@ export type PasswordFieldProps = UIBaseProps & {
18
18
  hideLabel: string;
19
19
  value?: string;
20
20
  inputRef?: (el: HTMLInputElement) => void;
21
- onInput?: (value: string) => void;
21
+ /**
22
+ * The new value.
23
+ *
24
+ * **Breaking in 3.1.** This was `onInput`, which named the DOM event while
25
+ * delivering a `string` — so it matched neither the native `onInput` (an
26
+ * `InputEvent`) nor the rest of the library (`onChange` with a value). It is
27
+ * `onChange` now, like every other control.
28
+ */
29
+ onChange?: (value: string) => void;
22
30
  onBlur?: () => void;
23
31
  visibleIcon?: JSX.Element;
24
32
  hiddenIcon?: JSX.Element;
@@ -54,7 +54,7 @@ const __solidLayoutPasswordFieldLayout = (_stable, p)=>{
54
54
  }), {
55
55
  ref: setFieldRef,
56
56
  onInput: (event)=>{
57
- p.onInput?.(event.currentTarget.value);
57
+ p.onChange?.(event.currentTarget.value);
58
58
  },
59
59
  onBlur: ()=>p.onBlur?.(),
60
60
  get endIcon () {
@@ -105,7 +105,7 @@ const PasswordFieldLayout = defineComponent({
105
105
  "hideLabel",
106
106
  "value",
107
107
  "inputRef",
108
- "onInput",
108
+ "onChange",
109
109
  "onBlur",
110
110
  "visibleIcon",
111
111
  "hiddenIcon",
@@ -53,8 +53,8 @@ export declare const createPasswordFieldInputContract: (params: PasswordFieldInp
53
53
  autocomplete: "off" | "current-password" | "new-password" | undefined;
54
54
  "aria-describedby": string | undefined;
55
55
  value: string | undefined;
56
- isDisabled: boolean;
57
- isInvalid: boolean;
56
+ disabled: boolean;
57
+ state: "invalid" | undefined;
58
58
  startIcon: JSX.Element;
59
59
  class: string;
60
60
  };
@@ -11,8 +11,8 @@ const createPasswordFieldInputContract = (params)=>({
11
11
  autocomplete: params.autocomplete,
12
12
  "aria-describedby": params["aria-describedby"],
13
13
  value: params.value,
14
- isDisabled: Boolean(params.disabled),
15
- isInvalid: Boolean(params.invalid),
14
+ disabled: Boolean(params.disabled),
15
+ state: params.invalid ? "invalid" : void 0,
16
16
  startIcon: params.startIcon,
17
17
  class: twMerge("w-full", params.inputClass)
18
18
  });
@@ -3,6 +3,7 @@ import { defineComponent } from "solid-layouts/solid-2/application-boundary";
3
3
  import "./Popover.css";
4
4
  import { Show, createContext, createMemo, createSignal, createTrackedEffect, omit, onSettled, useContext } from "solid-js";
5
5
  import { twMerge } from "../../lib/twMerge.js";
6
+ import { registerOverlay } from "../../lib/overlay.js";
6
7
  import "../_shared/material.css";
7
8
  import { applyBooleanStateRequest } from "../_shared/controlledState.js";
8
9
  import { createOverlayPosition } from "../_shared/overlayPosition.js";
@@ -52,20 +53,22 @@ const __solidLayoutPopoverRoot = (_stable, p)=>{
52
53
  focusTrigger: false
53
54
  });
54
55
  };
55
- const handleKeyDown = (event)=>{
56
- if (!isOpen()) return;
57
- if (false === p.closeOnEscape) return;
58
- if ("Escape" !== event.key) return;
59
- event.preventDefault();
60
- setIsOpen(false, {
61
- focusTrigger: true
62
- });
63
- };
64
56
  document.addEventListener("pointerdown", handlePointerDown);
65
- document.addEventListener("keydown", handleKeyDown);
66
57
  return ()=>{
67
58
  document.removeEventListener("pointerdown", handlePointerDown);
68
- document.removeEventListener("keydown", handleKeyDown);
59
+ };
60
+ });
61
+ createTrackedEffect(()=>{
62
+ if (!isOpen()) return;
63
+ const releaseOverlay = registerOverlay({
64
+ dismissable: ()=>false !== p.closeOnEscape,
65
+ dismiss: ()=>setIsOpen(false, {
66
+ focusTrigger: true
67
+ }),
68
+ element: ()=>contentRef() ?? void 0
69
+ });
70
+ return ()=>{
71
+ releaseOverlay();
69
72
  };
70
73
  });
71
74
  const ctx = {
@@ -1,13 +1,37 @@
1
1
  import type { Component as __LayoutComponent } from "solid-js";
2
2
  import "./Radio.css";
3
3
  import type { JSX } from "@solidjs/web";
4
- import type { UIBaseProps, State, Issue } from "../vocabulary";
5
- export type RadioProps = Omit<JSX.InputHTMLAttributes<HTMLInputElement>, "type" | "children"> & UIBaseProps & {
4
+ import type { Issue, State, UIBaseProps } from "../vocabulary";
5
+ export type RadioProps = Omit<JSX.InputHTMLAttributes<HTMLInputElement>, "type" | "children" | "onChange"> & UIBaseProps & {
6
6
  children?: JSX.Element;
7
7
  description?: JSX.Element;
8
8
  indicator?: JSX.Element;
9
9
  state?: State;
10
10
  issues?: Issue[];
11
+ /**
12
+ * Whether this radio is now the selected one.
13
+ *
14
+ * **Breaking in 3.1**, and the last control left out of it. Switch and
15
+ * Checkbox were changed to report their new value here while Radio was
16
+ * still handing over an `Event`, which is the inconsistency the change
17
+ * existed to remove -- swapping one control for another quietly changed
18
+ * what the handler received.
19
+ *
20
+ * A radio only ever reports `true`: deselection happens by another radio
21
+ * in the group being chosen, and that one reports itself. Reach for
22
+ * `RadioGroup`'s `onChange` when the question is which value is selected.
23
+ *
24
+ * The native handler is {@link onNativeChange}, and it is still where you
25
+ * call `preventDefault()`.
26
+ */
27
+ onChange?: (checked: boolean) => void;
28
+ /**
29
+ * The underlying `change` event, before the selection is applied.
30
+ *
31
+ * This is the veto: `preventDefault()` here leaves the group as it was and
32
+ * suppresses {@link onChange}.
33
+ */
34
+ onNativeChange?: JSX.EventHandlerUnion<HTMLInputElement, Event>;
11
35
  };
12
36
  declare const Radio: __LayoutComponent<RadioProps>;
13
37
  export default Radio;
@@ -4,8 +4,8 @@ import "./Radio.css";
4
4
  import { Show, omit, useContext } from "solid-js";
5
5
  import { twMerge } from "../../lib/twMerge.js";
6
6
  import { RadioGroupContext } from "../radio-group/context.js";
7
- import { CLASSES, componentRecipe } from "./Radio.recipe.js";
8
7
  import { resolveState } from "../vocabulary.js";
8
+ import { CLASSES, componentRecipe } from "./Radio.recipe.js";
9
9
  var _tmpl$ = /*#__PURE__*/ template("<span data-slot=label>"), _tmpl$2 = /*#__PURE__*/ template("<span>"), _tmpl$3 = /*#__PURE__*/ template("<span><!><!>"), _tmpl$4 = /*#__PURE__*/ template("<label><input><span><span>");
10
10
  const invokeEventHandler = (handler, event)=>{
11
11
  if ("function" == typeof handler) return void handler(event);
@@ -13,7 +13,7 @@ const invokeEventHandler = (handler, event)=>{
13
13
  };
14
14
  const __solidLayoutRadio = (_stable, p)=>{
15
15
  const group = useContext(RadioGroupContext);
16
- const others = omit(p, "class", "children", "description", "indicator", "state", "issues", "disabled", "checked", "value", "name", "onChange", "dataTheme", "aria-invalid");
16
+ const others = omit(p, "class", "children", "description", "indicator", "state", "issues", "disabled", "checked", "value", "name", "onChange", "onNativeChange", "dataTheme", "aria-invalid");
17
17
  const value = ()=>null != p.value ? String(p.value) : void 0;
18
18
  const isGrouped = ()=>Boolean(group && void 0 !== value());
19
19
  const isSelected = ()=>isGrouped() ? group?.value() === value() : Boolean(p.checked);
@@ -23,9 +23,11 @@ const __solidLayoutRadio = (_stable, p)=>{
23
23
  const ariaInvalid = ()=>p["aria-invalid"] ?? (isInvalid() ? true : void 0);
24
24
  const hasContent = ()=>null != p.children || null != p.description;
25
25
  const handleChange = (event)=>{
26
- invokeEventHandler(p.onChange, event);
26
+ invokeEventHandler(p.onNativeChange, event);
27
27
  if (event.defaultPrevented) return;
28
- if (event.currentTarget.checked && group && void 0 !== value()) group.selectValue(value(), event);
28
+ const checked = event.currentTarget.checked;
29
+ if (checked && group && void 0 !== value()) group.selectValue(value(), event);
30
+ p.onChange?.(checked);
29
31
  };
30
32
  var _el$ = _tmpl$4(), _el$2 = _el$.firstChild, _el$3 = _el$2.nextSibling, _el$4 = _el$3.firstChild;
31
33
  spread(_el$, mergeProps(()=>({
@@ -133,7 +135,9 @@ const Radio = defineComponent({
133
135
  "description",
134
136
  "indicator",
135
137
  "state",
136
- "issues"
138
+ "issues",
139
+ "onChange",
140
+ "onNativeChange"
137
141
  ]
138
142
  });
139
143
  const Radio_generated = Radio;