@pathscale/ui 3.0.0 → 3.2.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 (103) hide show
  1. package/README.md +13 -2
  2. package/dist/components/accordion/Accordion.css +24 -1
  3. package/dist/components/alert/Alert.css +11 -1
  4. package/dist/components/auth-field-group/AuthFieldGroup.css +11 -3
  5. package/dist/components/button/Button.css +37 -10
  6. package/dist/components/calendar/Calendar.generated.d.ts +19 -2
  7. package/dist/components/calendar/Calendar.generated.js +30 -23
  8. package/dist/components/calendar/index.d.ts +1 -1
  9. package/dist/components/card/Card.generated.d.ts +38 -2
  10. package/dist/components/card/Card.generated.js +99 -45
  11. package/dist/components/card/Card.interactions.d.ts +70 -0
  12. package/dist/components/card/Card.interactions.js +19 -0
  13. package/dist/components/card/index.d.ts +1 -1
  14. package/dist/components/checkbox/Checkbox.generated.d.ts +23 -2
  15. package/dist/components/checkbox/Checkbox.generated.js +14 -6
  16. package/dist/components/collapsible/Collapsible.css +17 -1
  17. package/dist/components/color-wheel-flower/ColorWheelFlower.generated.d.ts +8 -0
  18. package/dist/components/color-wheel-flower/ColorWheelFlower.generated.js +14 -1
  19. package/dist/components/color-wheel-flower/colorWheelFlowerContext.d.ts +9 -2
  20. package/dist/components/color-wheel-flower/colorWheelFlowerContext.js +2 -4
  21. package/dist/components/connection-settings/ConnectionSettings.css +76 -0
  22. package/dist/components/connection-settings/ConnectionSettings.generated.d.ts +45 -0
  23. package/dist/components/connection-settings/ConnectionSettings.generated.js +300 -0
  24. package/dist/components/connection-settings/ConnectionSettings.recipe.d.ts +54 -0
  25. package/dist/components/connection-settings/ConnectionSettings.recipe.js +111 -0
  26. package/dist/components/connection-settings/index.d.ts +2 -0
  27. package/dist/components/connection-settings/index.js +1 -0
  28. package/dist/components/date-picker/DatePicker.generated.d.ts +3 -1
  29. package/dist/components/date-picker/DatePicker.generated.js +8 -5
  30. package/dist/components/date-range-picker/DateRangePicker.generated.d.ts +3 -1
  31. package/dist/components/date-range-picker/DateRangePicker.generated.js +9 -6
  32. package/dist/components/dialog/Dialog.generated.js +17 -79
  33. package/dist/components/drawer/Drawer.a11y.d.ts +1 -3
  34. package/dist/components/drawer/Drawer.a11y.js +2 -30
  35. package/dist/components/drawer/Drawer.generated.d.ts +24 -0
  36. package/dist/components/drawer/Drawer.generated.js +65 -58
  37. package/dist/components/grid/Grid.generated.js +3 -3
  38. package/dist/components/icon/Icon.generated.d.ts +15 -0
  39. package/dist/components/icon/Icon.generated.js +11 -2
  40. package/dist/components/immersive-landing/ImmersiveLanding.css +1 -1
  41. package/dist/components/immersive-landing/components/CookieConsent.interactions.d.ts +24 -0
  42. package/dist/components/immersive-landing/components/CookieConsent.interactions.js +2 -0
  43. package/dist/components/immersive-landing/components/CookieConsent.js +52 -47
  44. package/dist/components/immersive-landing/components/FirefoxPWABanner.js +10 -10
  45. package/dist/components/immersive-landing/types.d.ts +15 -0
  46. package/dist/components/input/Input.css +5 -3
  47. package/dist/components/input/Input.generated.js +6 -3
  48. package/dist/components/language-switcher/LanguageSwitcher.generated.js +1 -1
  49. package/dist/components/live-chat/LiveChatPanel.generated.js +2 -6
  50. package/dist/components/live-chat/LiveChatPanel.interactions.d.ts +21 -0
  51. package/dist/components/live-chat/LiveChatPanel.interactions.js +10 -0
  52. package/dist/components/password-field/PasswordField.generated.d.ts +9 -1
  53. package/dist/components/password-field/PasswordField.generated.js +2 -2
  54. package/dist/components/password-field/PasswordField.interactions.d.ts +2 -2
  55. package/dist/components/password-field/PasswordField.interactions.js +2 -2
  56. package/dist/components/popover/Popover.a11y.d.ts +47 -0
  57. package/dist/components/popover/Popover.a11y.js +19 -0
  58. package/dist/components/popover/Popover.generated.d.ts +26 -0
  59. package/dist/components/popover/Popover.generated.js +119 -46
  60. package/dist/components/radio/Radio.generated.d.ts +26 -2
  61. package/dist/components/radio/Radio.generated.js +9 -5
  62. package/dist/components/range-calendar/RangeCalendar.generated.d.ts +3 -1
  63. package/dist/components/range-calendar/RangeCalendar.generated.js +4 -1
  64. package/dist/components/select/Select.generated.js +5 -0
  65. package/dist/components/slider/Slider.generated.d.ts +14 -1
  66. package/dist/components/slider/Slider.generated.js +3 -2
  67. package/dist/components/switch/Switch.css +0 -3
  68. package/dist/components/switch/Switch.generated.d.ts +23 -2
  69. package/dist/components/switch/Switch.generated.js +21 -44
  70. package/dist/components/switch/Switch.recipe.d.ts +61 -38
  71. package/dist/components/switch/Switch.recipe.js +88 -68
  72. package/dist/components/table/MobileListView.generated.js +1 -1
  73. package/dist/components/text/Text.generated.d.ts +26 -1
  74. package/dist/components/text/Text.generated.js +14 -13
  75. package/dist/components/text/Text.recipe.d.ts +17 -5
  76. package/dist/components/text/Text.recipe.js +7 -13
  77. package/dist/components/text/index.d.ts +1 -1
  78. package/dist/components/theme-color-picker/ThemeColorPicker.generated.js +1 -1
  79. package/dist/hooks/connection/createConnectionSettings.d.ts +128 -0
  80. package/dist/hooks/connection/createConnectionSettings.js +211 -0
  81. package/dist/hooks/connection/index.d.ts +2 -0
  82. package/dist/hooks/connection/index.js +1 -0
  83. package/dist/hooks/date/date.names.d.ts +107 -0
  84. package/dist/hooks/date/date.names.js +74 -0
  85. package/dist/hooks/date/date.utils.d.ts +11 -1
  86. package/dist/hooks/date/date.utils.js +3 -6
  87. package/dist/hooks/date/index.d.ts +1 -0
  88. package/dist/hooks/date/index.js +1 -0
  89. package/dist/hooks/date/useCalendarState.d.ts +12 -5
  90. package/dist/hooks/date/useCalendarState.js +7 -19
  91. package/dist/hooks/form/createForm.d.ts +4 -4
  92. package/dist/hooks/form/createForm.js +7 -9
  93. package/dist/index.d.ts +8 -4
  94. package/dist/index.js +3 -1
  95. package/dist/layouts.manifest.json +4 -1
  96. package/dist/lib/focus.d.ts +31 -0
  97. package/dist/lib/focus.js +39 -0
  98. package/dist/lib/overlay.d.ts +94 -0
  99. package/dist/lib/overlay.js +72 -0
  100. package/dist/purge-manifest.json +14427 -15269
  101. package/dist/responsive-classes.txt +450 -0
  102. package/dist/styles/base/index.css +42 -0
  103. package/package.json +11 -6
@@ -1,43 +1,66 @@
1
- export declare const CLASSES: {
2
- readonly base: "switch";
3
- readonly slot: {
4
- readonly input: "switch__input";
5
- readonly control: "switch__control";
6
- readonly thumb: "switch__thumb";
7
- readonly icon: "switch__icon";
8
- readonly content: "switch__content";
9
- readonly description: "switch__description";
10
- };
11
- readonly flavor: {
12
- readonly neutral: "switch--flavor-neutral";
13
- readonly primary: "switch--flavor-primary";
14
- readonly secondary: "switch--flavor-secondary";
15
- readonly accent: "switch--flavor-accent";
16
- readonly destructive: "switch--flavor-destructive";
17
- readonly success: "switch--flavor-success";
18
- readonly warning: "switch--flavor-warning";
19
- readonly info: "switch--flavor-info";
20
- };
21
- readonly size: {
22
- readonly sm: "switch--sm";
23
- readonly md: "switch--md";
24
- readonly lg: "switch--lg";
25
- };
26
- readonly flag: {
27
- readonly disabled: "switch--disabled";
28
- };
29
- };
1
+ /**
2
+ * Presentation, owned here rather than assembled in the component.
3
+ *
4
+ * The recipe declared nine empty slots while `Switch.layout.tsx` kept a
5
+ * `CLASSES` table and built the root's class with `twMerge` over base, size,
6
+ * flavor and a disabled flag. The slot names it declared did not match what the
7
+ * component rendered either -- `label` and `switch` were never used, and the
8
+ * classes lived somewhere else entirely.
9
+ *
10
+ * `flavor` and `size` are call-site props. `disabled` is computed from
11
+ * `props.disabled`, `props.state` and the enclosing group, so it is `state`:
12
+ * the compiler mirrors it to `data-disabled`, which is what the component was
13
+ * already setting by hand alongside the class.
14
+ */
30
15
  export declare const componentRecipe: import("solid-layouts/solid-2").Recipe<{
31
16
  readonly component: "switch";
17
+ readonly element: "label";
32
18
  readonly slots: {
33
- readonly description: {};
34
- readonly label: {};
35
- readonly root: {};
36
- readonly switch: {};
37
- readonly "switch-content": {};
38
- readonly "switch-control": {};
39
- readonly "switch-icon": {};
40
- readonly "switch-input": {};
41
- readonly "switch-thumb": {};
19
+ readonly root: {
20
+ readonly base: "switch";
21
+ };
22
+ readonly input: {
23
+ readonly base: "switch__input";
24
+ };
25
+ readonly control: {
26
+ readonly base: "switch__control";
27
+ };
28
+ readonly thumb: {
29
+ readonly base: "switch__thumb";
30
+ };
31
+ readonly icon: {
32
+ readonly base: "switch__icon";
33
+ };
34
+ readonly content: {
35
+ readonly base: "switch__content";
36
+ };
37
+ readonly label: {
38
+ readonly slot: "label";
39
+ };
40
+ readonly description: {
41
+ readonly base: "switch__description";
42
+ readonly slot: "description";
43
+ };
44
+ };
45
+ readonly props: {
46
+ readonly flavor: {
47
+ readonly neutral: "switch--flavor-neutral";
48
+ readonly primary: "switch--flavor-primary";
49
+ readonly secondary: "switch--flavor-secondary";
50
+ readonly accent: "switch--flavor-accent";
51
+ readonly destructive: "switch--flavor-destructive";
52
+ readonly success: "switch--flavor-success";
53
+ readonly warning: "switch--flavor-warning";
54
+ readonly info: "switch--flavor-info";
55
+ };
56
+ readonly size: {
57
+ readonly sm: "switch--sm";
58
+ readonly md: "switch--md";
59
+ readonly lg: "switch--lg";
60
+ };
61
+ };
62
+ readonly defaults: {
63
+ readonly flavor: "accent";
64
+ readonly size: "md";
42
65
  };
43
66
  }>;
@@ -1,97 +1,117 @@
1
1
  import { recipe } from "../../lib/layouts/index.js";
2
- const CLASSES = {
3
- base: "switch",
4
- slot: {
5
- input: "switch__input",
6
- control: "switch__control",
7
- thumb: "switch__thumb",
8
- icon: "switch__icon",
9
- content: "switch__content",
10
- description: "switch__description"
11
- },
12
- flavor: {
13
- neutral: "switch--flavor-neutral",
14
- primary: "switch--flavor-primary",
15
- secondary: "switch--flavor-secondary",
16
- accent: "switch--flavor-accent",
17
- destructive: "switch--flavor-destructive",
18
- success: "switch--flavor-success",
19
- warning: "switch--flavor-warning",
20
- info: "switch--flavor-info"
21
- },
22
- size: {
23
- sm: "switch--sm",
24
- md: "switch--md",
25
- lg: "switch--lg"
26
- },
27
- flag: {
28
- disabled: "switch--disabled"
29
- }
30
- };
31
2
  const componentRecipe = recipe({
32
3
  component: "switch",
4
+ element: "label",
33
5
  slots: {
34
- description: {},
35
- label: {},
36
- root: {},
37
- switch: {},
38
- "switch-content": {},
39
- "switch-control": {},
40
- "switch-icon": {},
41
- "switch-input": {},
42
- "switch-thumb": {}
6
+ root: {
7
+ base: "switch"
8
+ },
9
+ input: {
10
+ base: "switch__input"
11
+ },
12
+ control: {
13
+ base: "switch__control"
14
+ },
15
+ thumb: {
16
+ base: "switch__thumb"
17
+ },
18
+ icon: {
19
+ base: "switch__icon"
20
+ },
21
+ content: {
22
+ base: "switch__content"
23
+ },
24
+ label: {
25
+ slot: "label"
26
+ },
27
+ description: {
28
+ base: "switch__description",
29
+ slot: "description"
30
+ }
31
+ },
32
+ props: {
33
+ flavor: {
34
+ neutral: "switch--flavor-neutral",
35
+ primary: "switch--flavor-primary",
36
+ secondary: "switch--flavor-secondary",
37
+ accent: "switch--flavor-accent",
38
+ destructive: "switch--flavor-destructive",
39
+ success: "switch--flavor-success",
40
+ warning: "switch--flavor-warning",
41
+ info: "switch--flavor-info"
42
+ },
43
+ size: {
44
+ sm: "switch--sm",
45
+ md: "switch--md",
46
+ lg: "switch--lg"
47
+ }
48
+ },
49
+ defaults: {
50
+ flavor: "accent",
51
+ size: "md"
43
52
  },
44
53
  _layouts: {
45
54
  slots: {
46
- description: {
47
- base: "",
48
- axes: {}
49
- },
50
- label: {
51
- base: "",
52
- axes: {}
53
- },
54
55
  root: {
55
- base: "",
56
+ base: "switch",
57
+ axes: {
58
+ flavor: {
59
+ neutral: "switch--flavor-neutral",
60
+ primary: "switch--flavor-primary",
61
+ secondary: "switch--flavor-secondary",
62
+ accent: "switch--flavor-accent",
63
+ destructive: "switch--flavor-destructive",
64
+ success: "switch--flavor-success",
65
+ warning: "switch--flavor-warning",
66
+ info: "switch--flavor-info"
67
+ },
68
+ size: {
69
+ sm: "switch--sm",
70
+ md: "switch--md",
71
+ lg: "switch--lg"
72
+ }
73
+ }
74
+ },
75
+ input: {
76
+ base: "switch__input",
56
77
  axes: {}
57
78
  },
58
- switch: {
59
- base: "",
79
+ control: {
80
+ base: "switch__control",
60
81
  axes: {}
61
82
  },
62
- "switch-content": {
63
- base: "",
83
+ thumb: {
84
+ base: "switch__thumb",
64
85
  axes: {}
65
86
  },
66
- "switch-control": {
67
- base: "",
87
+ icon: {
88
+ base: "switch__icon",
68
89
  axes: {}
69
90
  },
70
- "switch-icon": {
71
- base: "",
91
+ content: {
92
+ base: "switch__content",
72
93
  axes: {}
73
94
  },
74
- "switch-input": {
95
+ label: {
75
96
  base: "",
76
97
  axes: {}
77
98
  },
78
- "switch-thumb": {
79
- base: "",
99
+ description: {
100
+ base: "switch__description",
80
101
  axes: {}
81
102
  }
82
103
  },
83
104
  stateKeys: [],
84
105
  slotIds: {
85
- description: 0,
86
- label: 1,
87
- root: 2,
88
- switch: 3,
89
- "switch-content": 4,
90
- "switch-control": 5,
91
- "switch-icon": 6,
92
- "switch-input": 7,
93
- "switch-thumb": 8
106
+ root: 6,
107
+ input: 4,
108
+ control: 1,
109
+ thumb: 7,
110
+ icon: 3,
111
+ content: 0,
112
+ label: 5,
113
+ description: 2
94
114
  }
95
115
  }
96
116
  });
97
- export { CLASSES, componentRecipe };
117
+ export { componentRecipe };
@@ -23,7 +23,7 @@ const __solidLayoutMobileListView = (_stable, p)=>{
23
23
  get children () {
24
24
  return createComponent(icon, {
25
25
  get src () {
26
- return p.emptyIcon ?? "icon-[mdi--inbox-outline]";
26
+ return p.emptyIcon ?? "icon-[lucide--inbox]";
27
27
  },
28
28
  width: 24,
29
29
  height: 24
@@ -1,6 +1,6 @@
1
1
  import type { Component as __LayoutComponent } from "solid-js";
2
2
  import "./Text.css";
3
- import type { JSX } from "@solidjs/web";
3
+ import { type JSX } from "@solidjs/web";
4
4
  import type { UIBaseProps } from "../vocabulary";
5
5
  export type TextSize = "xs" | "sm" | "base" | "lg" | "xl";
6
6
  export type TextVariant = "default" | "muted" | "subtle" | "success" | "warning" | "danger";
@@ -9,6 +9,16 @@ export type TextTransform = "none" | "uppercase" | "lowercase" | "capitalize";
9
9
  export type TextTracking = "normal" | "wide";
10
10
  export type TextLeading = "normal" | "none";
11
11
  export type TextFamily = "body" | "heading" | "display" | "mono";
12
+ /**
13
+ * The elements `Text` will render as.
14
+ *
15
+ * Deliberately a closed list rather than `keyof JSX.IntrinsicElements`. The
16
+ * point of the prop is to let a title *be* a heading, and an open list makes
17
+ * that one option among two hundred, most of which are wrong for a run of
18
+ * text. Six heading levels, the three neutral containers, and the two
19
+ * inline emphases that carry meaning of their own.
20
+ */
21
+ export type TextAs = "span" | "p" | "div" | "h1" | "h2" | "h3" | "h4" | "h5" | "h6" | "strong" | "em";
12
22
  export type TextRootProps = Omit<JSX.HTMLAttributes<HTMLSpanElement>, "color"> & UIBaseProps & {
13
23
  size?: TextSize;
14
24
  variant?: TextVariant;
@@ -17,6 +27,21 @@ export type TextRootProps = Omit<JSX.HTMLAttributes<HTMLSpanElement>, "color"> &
17
27
  tracking?: TextTracking;
18
28
  leading?: TextLeading;
19
29
  family?: TextFamily;
30
+ /**
31
+ * The element this text is.
32
+ *
33
+ * `span` by default, which is what it has always been and what a run of
34
+ * text inside a sentence should stay. Reach for this whenever the text is
35
+ * structural: `as="h1"` for a page title, `as="h2"` for a section, `as="p"`
36
+ * for a paragraph.
37
+ *
38
+ * `family="heading"` is a *typeface*: it says which face to set the text
39
+ * in, and it has never said anything about the document. Sites read the
40
+ * two as one thing and styled titles that were not headings, so entire
41
+ * pages, landing pages included, had no heading of any role on them and no
42
+ * way for a reader to move between sections. This is the axis that says so.
43
+ */
44
+ as?: TextAs;
20
45
  children?: JSX.Element;
21
46
  };
22
47
  declare const TextRoot: __LayoutComponent<TextRootProps>;
@@ -1,19 +1,18 @@
1
- import { insert, mergeProps, spread, template } from "@solidjs/web";
1
+ import { Dynamic, createComponent, mergeProps } from "@solidjs/web";
2
2
  import { defineComponent } from "solid-layouts/solid-2/application-boundary";
3
3
  import "./Text.css";
4
4
  import { omit } from "solid-js";
5
- import { twMerge } from "../../lib/twMerge.js";
6
- import { CLASSES, componentRecipe } from "./Text.recipe.js";
7
- var _tmpl$ = /*#__PURE__*/ template("<span>");
5
+ import { componentRecipe } from "./Text.recipe.js";
8
6
  const __solidLayoutTextRoot = (_stable, p)=>{
9
- const others = omit(p, "children", "class", "dataTheme", "style", "size", "variant", "weight", "transform", "tracking", "leading", "family");
7
+ const others = omit(p, "children", "class", "dataTheme", "style", "size", "variant", "weight", "transform", "tracking", "leading", "family", "as");
10
8
  const size = ()=>p.size ?? "base";
11
9
  const variant = ()=>p.variant ?? "default";
12
- var _el$ = _tmpl$();
13
- spread(_el$, mergeProps(others, ()=>({
14
- class: twMerge(CLASSES.base, p.class)
15
- }), {
16
- "data-slot": "text",
10
+ const tag = ()=>p.as ?? "span";
11
+ return createComponent(Dynamic, mergeProps({
12
+ get component () {
13
+ return tag();
14
+ }
15
+ }, others, ()=>_stable.slot.root, {
17
16
  get ["data-size"] () {
18
17
  return size();
19
18
  },
@@ -40,10 +39,11 @@ const __solidLayoutTextRoot = (_stable, p)=>{
40
39
  },
41
40
  get style () {
42
41
  return p.style;
42
+ },
43
+ get children () {
44
+ return p.children;
43
45
  }
44
- }), true);
45
- insert(_el$, ()=>p.children);
46
- return _el$;
46
+ }));
47
47
  };
48
48
  const TextRoot = defineComponent({
49
49
  recipe: componentRecipe,
@@ -57,6 +57,7 @@ const TextRoot = defineComponent({
57
57
  "tracking",
58
58
  "leading",
59
59
  "family",
60
+ "as",
60
61
  "children"
61
62
  ]
62
63
  });
@@ -1,10 +1,22 @@
1
- export declare const CLASSES: {
2
- readonly base: "text";
3
- };
1
+ /**
2
+ * The root class, owned here.
3
+ *
4
+ * Text's presentation axes stay `data-*` attributes rather than becoming recipe
5
+ * `props`, and deliberately: `Text.css` selects on `[data-size]`, `[data-variant]`
6
+ * and the rest, so turning them into recipe props would emit classes nothing
7
+ * styles. Recipe `props` map a value to a class; these map a value to an
8
+ * attribute, which is what `state` is for -- except these are set at the call
9
+ * site, not computed.
10
+ *
11
+ * So the only thing that was manual here is the base class, and that is what
12
+ * moves: the layout spreads `{...slot.root}` instead of calling `twMerge`.
13
+ */
4
14
  export declare const componentRecipe: import("solid-layouts/solid-2").Recipe<{
5
15
  readonly component: "text";
16
+ readonly element: "span";
6
17
  readonly slots: {
7
- readonly root: {};
8
- readonly text: {};
18
+ readonly root: {
19
+ readonly base: "text";
20
+ };
9
21
  };
10
22
  }>;
@@ -1,29 +1,23 @@
1
1
  import { recipe } from "../../lib/layouts/index.js";
2
- const CLASSES = {
3
- base: "text"
4
- };
5
2
  const componentRecipe = recipe({
6
3
  component: "text",
4
+ element: "span",
7
5
  slots: {
8
- root: {},
9
- text: {}
6
+ root: {
7
+ base: "text"
8
+ }
10
9
  },
11
10
  _layouts: {
12
11
  slots: {
13
12
  root: {
14
- base: "",
15
- axes: {}
16
- },
17
- text: {
18
- base: "",
13
+ base: "text",
19
14
  axes: {}
20
15
  }
21
16
  },
22
17
  stateKeys: [],
23
18
  slotIds: {
24
- root: 0,
25
- text: 1
19
+ root: 0
26
20
  }
27
21
  }
28
22
  });
29
- export { CLASSES, componentRecipe };
23
+ export { componentRecipe };
@@ -1 +1 @@
1
- export { default, Text, type TextFamily, type TextLeading, type TextProps, TextRoot, type TextRootProps, type TextSize, type TextTracking, type TextTransform, type TextVariant, type TextWeight, } from "./Text.generated";
1
+ export { default, Text, type TextAs, type TextFamily, type TextLeading, type TextProps, TextRoot, type TextRootProps, type TextSize, type TextTracking, type TextTransform, type TextVariant, type TextWeight, } from "./Text.generated";
@@ -141,7 +141,7 @@ const __solidLayoutThemeColorPicker = (_stable, p)=>{
141
141
  },
142
142
  get children () {
143
143
  return p.children ?? createComponent(icon, mergeProps({
144
- src: "icon-[mdi--palette]",
144
+ src: "icon-[lucide--palette]",
145
145
  width: 16,
146
146
  height: 16
147
147
  }, ()=>({
@@ -0,0 +1,128 @@
1
+ import type { Accessor } from "solid-js";
2
+ /**
3
+ * Where an application points itself, and how that survives a reload.
4
+ *
5
+ * Every property in this family ships a "connection settings" page: a toggle,
6
+ * one or more backend URLs, an app id, and a save that reconfigures the
7
+ * transport. Six of them had written it separately, in two different shapes and
8
+ * with different bugs, which is what this replaces.
9
+ *
10
+ * The storage model is per-endpoint rather than global. Four sites had a single
11
+ * `useCustomUrl` covering every backend at once; two had already grown a flag
12
+ * per backend, because pointing the API at a local instance while leaving auth
13
+ * on production is the ordinary case. Per-endpoint is the shape that covers
14
+ * both, and {@link ConnectionSettingsStore.setUseCustom} flips them together
15
+ * for a page that only wants one switch.
16
+ */
17
+ export interface ConnectionEndpoint {
18
+ /** Stable key. Names the value in storage and in {@link ConnectionSettingsStore.urls}. */
19
+ name: string;
20
+ /** The address used whenever this endpoint's override is off. */
21
+ fallback: string;
22
+ /**
23
+ * Reject an address before it is saved. Return a message to refuse it, or
24
+ * nothing to accept.
25
+ *
26
+ * Defaults to {@link isAbsoluteUrl}: the value has to parse as an absolute
27
+ * URL. That is deliberately weak, because this hook does not know what a
28
+ * given endpoint speaks. An endpoint that knows should say so -- a WebSocket
29
+ * transport handed `http://…` fails at connect time, long after the page
30
+ * that could have explained it has gone.
31
+ */
32
+ validate?: (url: string) => string | undefined;
33
+ }
34
+ /** What {@link ConnectionSettingsStore.apply} hands to `onApply`. */
35
+ export interface ConnectionSettingsApplied {
36
+ /** Resolved per endpoint, overrides taken into account. Never empty. */
37
+ urls: Readonly<Record<string, string>>;
38
+ appPublicId: string;
39
+ /** Which endpoints the resolved address came from an override for. */
40
+ overrides: Readonly<Record<string, boolean>>;
41
+ }
42
+ /**
43
+ * Whether a bracketed host is an IPv6 literal.
44
+ *
45
+ * `https://[1:2:3]` is not an address, and a character class of hex digits and
46
+ * colons said it was. This is the shape the URL Standard describes: eight
47
+ * 16-bit groups, or fewer with exactly one `::` standing for the run of zeroes
48
+ * it elides, optionally ending in a dotted IPv4 form.
49
+ *
50
+ * Written out rather than folded into one pattern because the `::` rule is a
51
+ * count, not a shape: each half has to parse, and together they have to leave
52
+ * at least one group for the `::` to stand for.
53
+ */
54
+ export declare const isIpv6Literal: (host: string) => boolean;
55
+ export declare const isAbsoluteUrl: (url: string) => string | undefined;
56
+ export interface ConnectionSettingsOptions {
57
+ /** `localStorage` key. Namespace it per application; two apps on one origin would collide. */
58
+ storageKey: string;
59
+ endpoints: readonly ConnectionEndpoint[];
60
+ /** The application's own id, when it has one. Stored alongside the URLs. */
61
+ appPublicId?: string;
62
+ /**
63
+ * Run after a successful save or reset, with everything that was applied.
64
+ *
65
+ * This is where an application reconfigures its transport. It is awaited, so
66
+ * `isApplying` covers the reconnect rather than just the write.
67
+ *
68
+ * It receives the whole applied state, not only the URLs: a site that stores
69
+ * an app id here reconfigures its identity from the same call, and passing
70
+ * the URLs alone left it reaching back into the store it had just handed to
71
+ * this hook.
72
+ */
73
+ onApply?: (applied: ConnectionSettingsApplied) => void | Promise<void>;
74
+ }
75
+ export interface ConnectionSettingsState {
76
+ /** Per endpoint: is the override in use. Absent means no. */
77
+ overrides: Record<string, boolean>;
78
+ /** Per endpoint: the address to use when its override is on. */
79
+ urls: Record<string, string>;
80
+ appPublicId: string;
81
+ }
82
+ export interface ConnectionSettingsStore {
83
+ /** What is stored, override flags included. Read this to populate a form. */
84
+ readonly state: ConnectionSettingsState;
85
+ /**
86
+ * The address for each endpoint after overrides are applied. This is what a
87
+ * transport should read; it never contains an empty string.
88
+ */
89
+ readonly urls: Readonly<Record<string, string>>;
90
+ /** The address each endpoint falls back to, by name. What "not overridden" means. */
91
+ readonly fallbacks: Readonly<Record<string, string>>;
92
+ /** True while `onApply` is in flight. */
93
+ readonly isApplying: boolean;
94
+ /** Nothing has been overridden and the app id is untouched. */
95
+ readonly isAtDefaults: boolean;
96
+ /** True when this endpoint is overridden. */
97
+ isOverridden(name: string): boolean;
98
+ /**
99
+ * Why this address cannot be saved for this endpoint, or `undefined` if it
100
+ * can. Empty is always refused; beyond that the endpoint's own `validate`
101
+ * decides, defaulting to {@link isAbsoluteUrl}.
102
+ *
103
+ * A settings page is the last place able to explain a bad address. Saved
104
+ * unchecked, the value survives a failed reconnect and is still there on the
105
+ * next launch, with nothing on screen saying why nothing connects.
106
+ */
107
+ validate(name: string, url: string): string | undefined;
108
+ /**
109
+ * Set an endpoint's override.
110
+ *
111
+ * Returns the reason it was refused, or `undefined` when it was stored. A
112
+ * value written here becomes an active, persisted override, so it has to
113
+ * pass the same check {@link ConnectionSettingsStore.validate} applies;
114
+ * an invalid one is not stored at all. Keep it as a draft in the UI instead.
115
+ */
116
+ setUrl(name: string, url: string): string | undefined;
117
+ setOverride(name: string, on: boolean): void;
118
+ /** Flip every endpoint together, for a page with one switch. */
119
+ setUseCustom(on: boolean): void;
120
+ setAppPublicId(id: string): void;
121
+ /** Drop every override and forget the stored copy. Does not apply. */
122
+ reset(): void;
123
+ /** Persist, then hand the resolved addresses to `onApply`. */
124
+ apply(): Promise<void>;
125
+ /** For a component that wants to track the state rather than read it once. */
126
+ state$: Accessor<ConnectionSettingsState>;
127
+ }
128
+ export declare const createConnectionSettings: (options: ConnectionSettingsOptions) => ConnectionSettingsStore;