@viniaraujo68/plinth 0.0.0-stage → 0.3.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 (132) hide show
  1. package/LICENSE +21 -0
  2. package/README.md +361 -2
  3. package/dist/anchoring.d.ts +61 -0
  4. package/dist/anchoring.js +151 -0
  5. package/dist/async-action.svelte.d.ts +37 -0
  6. package/dist/async-action.svelte.js +64 -0
  7. package/dist/attachments/index.d.ts +2 -0
  8. package/dist/attachments/index.js +2 -0
  9. package/dist/attachments/sortable.d.ts +6 -0
  10. package/dist/attachments/sortable.js +227 -0
  11. package/dist/attachments/tooltip.d.ts +37 -0
  12. package/dist/attachments/tooltip.js +166 -0
  13. package/dist/components/AsyncButton.svelte +49 -0
  14. package/dist/components/AsyncButton.svelte.d.ts +32 -0
  15. package/dist/components/Combobox.svelte +380 -0
  16. package/dist/components/Combobox.svelte.d.ts +74 -0
  17. package/dist/components/Copyable.svelte +116 -0
  18. package/dist/components/Copyable.svelte.d.ts +37 -0
  19. package/dist/components/DateRangePicker.svelte +266 -0
  20. package/dist/components/DateRangePicker.svelte.d.ts +66 -0
  21. package/dist/components/Dialog.svelte +102 -0
  22. package/dist/components/Dialog.svelte.d.ts +38 -0
  23. package/dist/components/DragHandle.svelte +26 -0
  24. package/dist/components/DragHandle.svelte.d.ts +7 -0
  25. package/dist/components/Dropdown.svelte +204 -0
  26. package/dist/components/Dropdown.svelte.d.ts +49 -0
  27. package/dist/components/ErrorDisplay.svelte +59 -0
  28. package/dist/components/ErrorDisplay.svelte.d.ts +24 -0
  29. package/dist/components/ErrorPage.svelte +119 -0
  30. package/dist/components/ErrorPage.svelte.d.ts +52 -0
  31. package/dist/components/JsonInput.svelte +106 -0
  32. package/dist/components/JsonInput.svelte.d.ts +40 -0
  33. package/dist/components/Listbox.svelte +257 -0
  34. package/dist/components/Listbox.svelte.d.ts +78 -0
  35. package/dist/components/LoadingButton.svelte +36 -0
  36. package/dist/components/LoadingButton.svelte.d.ts +22 -0
  37. package/dist/components/Logo.svelte +112 -0
  38. package/dist/components/Logo.svelte.d.ts +29 -0
  39. package/dist/components/Modal.svelte +187 -0
  40. package/dist/components/Modal.svelte.d.ts +62 -0
  41. package/dist/components/MultiSelect.svelte +256 -0
  42. package/dist/components/MultiSelect.svelte.d.ts +89 -0
  43. package/dist/components/OptionPanel.svelte +241 -0
  44. package/dist/components/OptionPanel.svelte.d.ts +51 -0
  45. package/dist/components/Paginator.svelte +205 -0
  46. package/dist/components/Paginator.svelte.d.ts +48 -0
  47. package/dist/components/RefreshButton.svelte +246 -0
  48. package/dist/components/RefreshButton.svelte.d.ts +46 -0
  49. package/dist/components/SegmentedControl.svelte +147 -0
  50. package/dist/components/SegmentedControl.svelte.d.ts +71 -0
  51. package/dist/components/Select.svelte +312 -0
  52. package/dist/components/Select.svelte.d.ts +68 -0
  53. package/dist/components/Skeleton.svelte +97 -0
  54. package/dist/components/Skeleton.svelte.d.ts +32 -0
  55. package/dist/components/Tooltip.svelte +60 -0
  56. package/dist/components/Tooltip.svelte.d.ts +58 -0
  57. package/dist/components/date-range.d.ts +101 -0
  58. package/dist/components/date-range.js +144 -0
  59. package/dist/components/index.d.ts +26 -0
  60. package/dist/components/index.js +38 -0
  61. package/dist/components/json-text.d.ts +22 -0
  62. package/dist/components/json-text.js +22 -0
  63. package/dist/components/pick.d.ts +18 -0
  64. package/dist/components/pick.js +18 -0
  65. package/dist/components/segmented.d.ts +7 -0
  66. package/dist/components/segmented.js +1 -0
  67. package/dist/components/select.d.ts +66 -0
  68. package/dist/components/select.js +90 -0
  69. package/dist/confirm/Confirmer.svelte +194 -0
  70. package/dist/confirm/Confirmer.svelte.d.ts +45 -0
  71. package/dist/confirm/challenge.d.ts +16 -0
  72. package/dist/confirm/challenge.js +16 -0
  73. package/dist/confirm/confirm-manager.svelte.d.ts +91 -0
  74. package/dist/confirm/confirm-manager.svelte.js +149 -0
  75. package/dist/confirm/index.d.ts +3 -0
  76. package/dist/confirm/index.js +3 -0
  77. package/dist/error.d.ts +25 -0
  78. package/dist/error.js +39 -0
  79. package/dist/formatters.d.ts +95 -0
  80. package/dist/formatters.js +146 -0
  81. package/dist/http.d.ts +68 -0
  82. package/dist/http.js +138 -0
  83. package/dist/index.d.ts +10 -0
  84. package/dist/index.js +14 -0
  85. package/dist/routing.svelte.d.ts +169 -0
  86. package/dist/routing.svelte.js +208 -0
  87. package/dist/shell/AppShell.svelte +874 -0
  88. package/dist/shell/AppShell.svelte.d.ts +93 -0
  89. package/dist/shell/Breadcrumbs.svelte +78 -0
  90. package/dist/shell/Breadcrumbs.svelte.d.ts +25 -0
  91. package/dist/shell/crumbs.d.ts +23 -0
  92. package/dist/shell/crumbs.js +1 -0
  93. package/dist/shell/index.d.ts +3 -0
  94. package/dist/shell/index.js +6 -0
  95. package/dist/table/ColumnMenu.svelte +249 -0
  96. package/dist/table/ColumnMenu.svelte.d.ts +47 -0
  97. package/dist/table/DataTable.svelte +643 -0
  98. package/dist/table/DataTable.svelte.d.ts +153 -0
  99. package/dist/table/columns.d.ts +55 -0
  100. package/dist/table/columns.js +153 -0
  101. package/dist/table/index.d.ts +4 -0
  102. package/dist/table/index.js +8 -0
  103. package/dist/table/sort.d.ts +48 -0
  104. package/dist/table/sort.js +139 -0
  105. package/dist/table/types.d.ts +93 -0
  106. package/dist/table/types.js +1 -0
  107. package/dist/theme/ThemeController.svelte +54 -0
  108. package/dist/theme/ThemeController.svelte.d.ts +27 -0
  109. package/dist/theme/ThemeToggle.svelte +119 -0
  110. package/dist/theme/ThemeToggle.svelte.d.ts +52 -0
  111. package/dist/theme/css-color.d.ts +23 -0
  112. package/dist/theme/css-color.js +31 -0
  113. package/dist/theme/index.d.ts +4 -0
  114. package/dist/theme/index.js +5 -0
  115. package/dist/theme/theme.css +410 -0
  116. package/dist/theme/theme.svelte.d.ts +54 -0
  117. package/dist/theme/theme.svelte.js +58 -0
  118. package/dist/toast/Toaster.svelte +257 -0
  119. package/dist/toast/Toaster.svelte.d.ts +35 -0
  120. package/dist/toast/index.d.ts +2 -0
  121. package/dist/toast/index.js +2 -0
  122. package/dist/toast/toast-manager.svelte.d.ts +99 -0
  123. package/dist/toast/toast-manager.svelte.js +176 -0
  124. package/dist/user/ScopedComponent.svelte +47 -0
  125. package/dist/user/ScopedComponent.svelte.d.ts +29 -0
  126. package/dist/user/anonymous.d.ts +21 -0
  127. package/dist/user/anonymous.js +26 -0
  128. package/dist/user/context.d.ts +55 -0
  129. package/dist/user/context.js +13 -0
  130. package/dist/user/index.d.ts +3 -0
  131. package/dist/user/index.js +6 -0
  132. package/package.json +133 -4
@@ -0,0 +1,54 @@
1
+ <script lang="ts">
2
+ import { DARK_THEME, getThemeContext, LIGHT_THEME, themeCookie } from "./theme.svelte.js";
3
+
4
+ const theme = getThemeContext();
5
+
6
+ // A consumer that stamps `data-theme` on <html> before hydration is seeding the FIRST PAINT
7
+ // from a cookie no checkbox has read yet. CSS already makes a checked controller outrank that
8
+ // seed, but "system" checks nothing, so a stale seed would go on painting a theme the user has
9
+ // just left. Releasing it once, on mount, hands the root over to this checkbox for good; the
10
+ // effect reads nothing reactive, so it runs exactly once.
11
+ $effect(() => {
12
+ const root = document.documentElement;
13
+ const seed = root.getAttribute("data-theme");
14
+ if (seed === LIGHT_THEME || seed === DARK_THEME) root.removeAttribute("data-theme");
15
+ });
16
+
17
+ $effect(() => {
18
+ document.cookie = themeCookie(theme.preference);
19
+ });
20
+ </script>
21
+
22
+ <!--
23
+ @component
24
+ The daisyUI theme-controller checkbox, plus persistence of whatever it is holding.
25
+
26
+ The checkbox encodes the PREFERENCE, not the resolved theme: unchecked means "system", which the
27
+ stylesheet answers with `color-scheme: light dark` so the OS decides at first paint with no JS
28
+ involved; checked pins the theme named by `value`. All three states are therefore fully
29
+ determined by the cookie, which is what makes a server-rendered first paint flash-free.
30
+
31
+ A `data-theme` stamped on <html> before hydration — the head-script trick a client-rendered app
32
+ uses to avoid a flash — is a seed for that first paint and nothing more. This checkbox outranks
33
+ it as soon as it is checked, and drops the seed altogether on mount, so from then on the
34
+ preference is the only thing painting the page. A `data-theme` on any element BELOW the root is
35
+ untouched by all of this and keeps re-theming its own subtree.
36
+
37
+ Mount it exactly once and unconditionally, near the app root — unmounting it drops the app back
38
+ to "system". Nothing else in an app should carry the `theme-controller` class; a picker elsewhere
39
+ writes `preference` on the theme context and lets this component follow.
40
+
41
+ ```svelte
42
+ setThemeContext(new ThemeContext(readThemePreference()));
43
+ ...
44
+ <ThemeController />
45
+ ```
46
+ -->
47
+
48
+ <input
49
+ type="checkbox"
50
+ class="theme-controller"
51
+ value={theme.preference === "light" ? LIGHT_THEME : DARK_THEME}
52
+ hidden
53
+ checked={theme.preference !== "system"}
54
+ />
@@ -0,0 +1,27 @@
1
+ /**
2
+ * The daisyUI theme-controller checkbox, plus persistence of whatever it is holding.
3
+ *
4
+ * The checkbox encodes the PREFERENCE, not the resolved theme: unchecked means "system", which the
5
+ * stylesheet answers with `color-scheme: light dark` so the OS decides at first paint with no JS
6
+ * involved; checked pins the theme named by `value`. All three states are therefore fully
7
+ * determined by the cookie, which is what makes a server-rendered first paint flash-free.
8
+ *
9
+ * A `data-theme` stamped on <html> before hydration — the head-script trick a client-rendered app
10
+ * uses to avoid a flash — is a seed for that first paint and nothing more. This checkbox outranks
11
+ * it as soon as it is checked, and drops the seed altogether on mount, so from then on the
12
+ * preference is the only thing painting the page. A `data-theme` on any element BELOW the root is
13
+ * untouched by all of this and keeps re-theming its own subtree.
14
+ *
15
+ * Mount it exactly once and unconditionally, near the app root — unmounting it drops the app back
16
+ * to "system". Nothing else in an app should carry the `theme-controller` class; a picker elsewhere
17
+ * writes `preference` on the theme context and lets this component follow.
18
+ *
19
+ * ```svelte
20
+ * setThemeContext(new ThemeContext(readThemePreference()));
21
+ * ...
22
+ * <ThemeController />
23
+ * ```
24
+ */
25
+ declare const ThemeController: import("svelte").Component<Record<string, never>, {}, "">;
26
+ type ThemeController = ReturnType<typeof ThemeController>;
27
+ export default ThemeController;
@@ -0,0 +1,119 @@
1
+ <script lang="ts">
2
+ import { getThemeContext, type ThemePreference } from "./theme.svelte.js";
3
+
4
+ // Cycling through "system" rather than flipping between the two explicit themes is the point:
5
+ // "follow the OS" is a real choice a user can get back to, and a two-state toggle strands it.
6
+ const NEXT: Record<ThemePreference, ThemePreference> = {
7
+ system: "light",
8
+ light: "dark",
9
+ dark: "system",
10
+ };
11
+
12
+ const LABELS: Record<ThemePreference, string> = {
13
+ system: "System",
14
+ light: "Light",
15
+ dark: "Dark",
16
+ };
17
+
18
+ interface Props {
19
+ /** Extra classes for the button, so a caller can size or place it. */
20
+ class?: string;
21
+ /** Hide the written preference and keep only the icon. The accessible name is unaffected. */
22
+ iconOnly?: boolean;
23
+ /**
24
+ * Names one preference — the visible text, and the words the default accessible name is built
25
+ * from. A function of the preference, and not three strings, because it is the same wording in
26
+ * both places; overriding it localizes both at once.
27
+ */
28
+ preferenceLabel?: (preference: ThemePreference) => string;
29
+ /**
30
+ * Accessible name of the button, given the preference on screen and the one a click moves to.
31
+ * Defaults to the English sentence around `preferenceLabel`, so a caller who only needs the
32
+ * three words translated can leave this alone; supply it to phrase the whole sentence.
33
+ */
34
+ label?: (current: ThemePreference, next: ThemePreference) => string;
35
+ }
36
+
37
+ const {
38
+ class: className = "",
39
+ iconOnly = false,
40
+ preferenceLabel = (preference: ThemePreference) => LABELS[preference],
41
+ label,
42
+ }: Props = $props();
43
+
44
+ const theme = getThemeContext();
45
+
46
+ const next = $derived(NEXT[theme.preference]);
47
+
48
+ const accessibleName = $derived(
49
+ label?.(theme.preference, next) ??
50
+ `Theme: ${preferenceLabel(theme.preference)}. Switch to ${preferenceLabel(next)}.`,
51
+ );
52
+ </script>
53
+
54
+ <!--
55
+ @component
56
+ A visible control cycling the theme preference System → Light → Dark → System.
57
+
58
+ It only writes `preference` on the theme context; the actual repaint is done by the
59
+ `ThemeController` checkbox, which has to be mounted once near the app root. That split is what
60
+ lets an app place any number of pickers wherever it likes without ever duplicating the
61
+ `theme-controller` element, whose presence is what CSS keys on.
62
+
63
+ The wording is English by default and both halves of it are props, because the library ships no
64
+ translations. `preferenceLabel` names a single preference — the visible text and the words inside
65
+ the accessible name — and is usually the only one an app needs. `label` replaces the sentence those
66
+ words sit in, for a language the "Theme: X. Switch to Y." shape does not fit.
67
+
68
+ ```svelte
69
+ <script lang="ts">
70
+ import { ThemeToggle, type ThemePreference } from "@viniaraujo68/plinth/theme";
71
+
72
+ const PREFERENCES: Record<ThemePreference, string> = {
73
+ system: "Sistema",
74
+ light: "Claro",
75
+ dark: "Escuro",
76
+ };
77
+ </script>
78
+
79
+ <ThemeToggle
80
+ preferenceLabel={(preference) => PREFERENCES[preference]}
81
+ label={(current, next) => `Tema: ${PREFERENCES[current]}. Mudar para ${PREFERENCES[next]}.`}
82
+ />
83
+ ```
84
+ -->
85
+
86
+ <button
87
+ type="button"
88
+ class="btn gap-2 btn-ghost btn-sm {className}"
89
+ aria-label={accessibleName}
90
+ data-preference={theme.preference}
91
+ onclick={() => (theme.preference = next)}
92
+ >
93
+ <!-- aria-hidden because the button already carries the whole meaning in its accessible name. -->
94
+ <svg
95
+ class="size-4"
96
+ viewBox="0 0 24 24"
97
+ fill="none"
98
+ stroke="currentColor"
99
+ stroke-width="1.75"
100
+ stroke-linecap="round"
101
+ stroke-linejoin="round"
102
+ aria-hidden="true"
103
+ >
104
+ {#if theme.preference === "light"}
105
+ <circle cx="12" cy="12" r="4" />
106
+ <path
107
+ d="M12 2v2M12 20v2M4.9 4.9l1.4 1.4M17.7 17.7l1.4 1.4M2 12h2M20 12h2M4.9 19.1l1.4-1.4M17.7 6.3l1.4-1.4"
108
+ />
109
+ {:else if theme.preference === "dark"}
110
+ <path d="M21 12.8A9 9 0 1 1 11.2 3a7 7 0 0 0 9.8 9.8Z" />
111
+ {:else}
112
+ <rect x="2" y="4" width="20" height="13" rx="2" />
113
+ <path d="M8 21h8M12 17v4" />
114
+ {/if}
115
+ </svg>
116
+ {#if !iconOnly}
117
+ <span aria-hidden="true">{preferenceLabel(theme.preference)}</span>
118
+ {/if}
119
+ </button>
@@ -0,0 +1,52 @@
1
+ import { type ThemePreference } from "./theme.svelte.js";
2
+ interface Props {
3
+ /** Extra classes for the button, so a caller can size or place it. */
4
+ class?: string;
5
+ /** Hide the written preference and keep only the icon. The accessible name is unaffected. */
6
+ iconOnly?: boolean;
7
+ /**
8
+ * Names one preference — the visible text, and the words the default accessible name is built
9
+ * from. A function of the preference, and not three strings, because it is the same wording in
10
+ * both places; overriding it localizes both at once.
11
+ */
12
+ preferenceLabel?: (preference: ThemePreference) => string;
13
+ /**
14
+ * Accessible name of the button, given the preference on screen and the one a click moves to.
15
+ * Defaults to the English sentence around `preferenceLabel`, so a caller who only needs the
16
+ * three words translated can leave this alone; supply it to phrase the whole sentence.
17
+ */
18
+ label?: (current: ThemePreference, next: ThemePreference) => string;
19
+ }
20
+ /**
21
+ * A visible control cycling the theme preference System → Light → Dark → System.
22
+ *
23
+ * It only writes `preference` on the theme context; the actual repaint is done by the
24
+ * `ThemeController` checkbox, which has to be mounted once near the app root. That split is what
25
+ * lets an app place any number of pickers wherever it likes without ever duplicating the
26
+ * `theme-controller` element, whose presence is what CSS keys on.
27
+ *
28
+ * The wording is English by default and both halves of it are props, because the library ships no
29
+ * translations. `preferenceLabel` names a single preference — the visible text and the words inside
30
+ * the accessible name — and is usually the only one an app needs. `label` replaces the sentence those
31
+ * words sit in, for a language the "Theme: X. Switch to Y." shape does not fit.
32
+ *
33
+ * ```svelte
34
+ * <script lang="ts">
35
+ * import { ThemeToggle, type ThemePreference } from "@viniaraujo68/plinth/theme";
36
+ *
37
+ * const PREFERENCES: Record<ThemePreference, string> = {
38
+ * system: "Sistema",
39
+ * light: "Claro",
40
+ * dark: "Escuro",
41
+ * };
42
+ * </script>
43
+ *
44
+ * <ThemeToggle
45
+ * preferenceLabel={(preference) => PREFERENCES[preference]}
46
+ * label={(current, next) => `Tema: ${PREFERENCES[current]}. Mudar para ${PREFERENCES[next]}.`}
47
+ * />
48
+ * ```
49
+ */
50
+ declare const ThemeToggle: import("svelte").Component<Props, {}, "">;
51
+ type ThemeToggle = ReturnType<typeof ThemeToggle>;
52
+ export default ThemeToggle;
@@ -0,0 +1,23 @@
1
+ /**
2
+ * Resolves CSS colour expressions — `var(--color-primary)`, a `color-mix()` over theme tokens —
3
+ * into the concrete colour strings a canvas needs. A chart library draws on a `<canvas>`, which
4
+ * knows nothing of custom properties, so a chart that follows the theme has to ask the page what
5
+ * its tokens currently compute to, in the right place in the tree.
6
+ */
7
+ export interface CssColorReader {
8
+ /**
9
+ * The computed colour of `expression` inside the host, as `rgb(...)` or whatever the browser
10
+ * serialises it to. `fallback` answers for an expression the browser rejects — a typo, or a
11
+ * colour function it does not support yet.
12
+ */
13
+ read: (expression: string, fallback: string) => string;
14
+ /** Removes the probe element. Reads after this answer the fallback. */
15
+ dispose: () => void;
16
+ }
17
+ /**
18
+ * One hidden probe element, appended inside `host` so custom properties resolve against the host's
19
+ * own cascade — a theme scoped to a subtree, a palette declared on the chart's wrapper — rather
20
+ * than against the document root. The probe is reused for every read, since each one costs a style
21
+ * recalculation and a chart reads a dozen colours per render.
22
+ */
23
+ export declare const createCssColorReader: (host: HTMLElement) => CssColorReader;
@@ -0,0 +1,31 @@
1
+ /**
2
+ * One hidden probe element, appended inside `host` so custom properties resolve against the host's
3
+ * own cascade — a theme scoped to a subtree, a palette declared on the chart's wrapper — rather
4
+ * than against the document root. The probe is reused for every read, since each one costs a style
5
+ * recalculation and a chart reads a dozen colours per render.
6
+ */
7
+ export const createCssColorReader = (host) => {
8
+ const probe = document.createElement("span");
9
+ probe.style.position = "absolute";
10
+ probe.style.visibility = "hidden";
11
+ probe.style.pointerEvents = "none";
12
+ host.appendChild(probe);
13
+ let disposed = false;
14
+ return {
15
+ read(expression, fallback) {
16
+ if (disposed)
17
+ return fallback;
18
+ probe.style.color = "";
19
+ probe.style.color = expression;
20
+ // An expression the browser cannot parse leaves the declaration empty, and the computed
21
+ // colour would then be whatever the probe inherits — a colour, just not the one asked for.
22
+ if (probe.style.color === "")
23
+ return fallback;
24
+ return getComputedStyle(probe).color || fallback;
25
+ },
26
+ dispose() {
27
+ disposed = true;
28
+ probe.remove();
29
+ },
30
+ };
31
+ };
@@ -0,0 +1,4 @@
1
+ export { DARK_THEME, getThemeContext, LIGHT_THEME, parseThemePreference, readThemePreference, setThemeContext, THEME_COOKIE, ThemeContext, themeCookie, type ThemePreference, } from "./theme.svelte.js";
2
+ export { default as ThemeController } from "./ThemeController.svelte";
3
+ export { default as ThemeToggle } from "./ThemeToggle.svelte";
4
+ export { createCssColorReader, type CssColorReader } from "./css-color.js";
@@ -0,0 +1,5 @@
1
+ export { DARK_THEME, getThemeContext, LIGHT_THEME, parseThemePreference, readThemePreference, setThemeContext, THEME_COOKIE, ThemeContext, themeCookie, } from "./theme.svelte.js";
2
+ export { default as ThemeController } from "./ThemeController.svelte";
3
+ export { default as ThemeToggle } from "./ThemeToggle.svelte";
4
+ // Theme tokens resolved to concrete colours, for the one surface CSS cannot reach: a canvas.
5
+ export { createCssColorReader } from "./css-color.js";