@mystravil/hardpoint 0.2.0 → 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 (54) hide show
  1. package/CHANGELOG.md +51 -38
  2. package/LICENSE +25 -25
  3. package/README.md +67 -64
  4. package/dist/base.css +625 -625
  5. package/dist/components/AppShell.svelte +698 -698
  6. package/dist/components/Button.svelte +221 -174
  7. package/dist/components/Button.svelte.d.ts +18 -2
  8. package/dist/components/Checkbox.svelte +235 -235
  9. package/dist/components/CheckboxGroup.svelte +207 -207
  10. package/dist/components/Combobox.svelte +901 -901
  11. package/dist/components/Dialog.svelte +359 -359
  12. package/dist/components/Disclosure.svelte +201 -201
  13. package/dist/components/EmptyState.svelte +88 -88
  14. package/dist/components/ErrorState.svelte +135 -135
  15. package/dist/components/ImageViewer.svelte +764 -764
  16. package/dist/components/KeyValueList.svelte +114 -114
  17. package/dist/components/ListDetail.svelte +218 -218
  18. package/dist/components/LoadRegion.svelte +219 -219
  19. package/dist/components/MediaFrame.svelte +110 -110
  20. package/dist/components/MediaImage.svelte +256 -256
  21. package/dist/components/Menu.svelte +275 -258
  22. package/dist/components/MenuCheckboxItem.svelte +119 -119
  23. package/dist/components/MenuGroup.svelte +50 -50
  24. package/dist/components/MenuItem.svelte +94 -94
  25. package/dist/components/MenuRadioGroup.svelte +62 -62
  26. package/dist/components/MenuRadioItem.svelte +110 -110
  27. package/dist/components/MenuSeparator.svelte +28 -28
  28. package/dist/components/Meter.svelte +283 -283
  29. package/dist/components/NativeSelect.svelte +135 -135
  30. package/dist/components/Notice.svelte +262 -262
  31. package/dist/components/Popover.svelte +222 -222
  32. package/dist/components/Progress.svelte +157 -157
  33. package/dist/components/RadioGroup.svelte +440 -440
  34. package/dist/components/Select.svelte +471 -471
  35. package/dist/components/Skeleton.svelte +149 -149
  36. package/dist/components/Spinner.svelte +118 -118
  37. package/dist/components/Stat.svelte +253 -253
  38. package/dist/components/Steps.svelte +189 -189
  39. package/dist/components/Switch.svelte +222 -222
  40. package/dist/components/Table.svelte +504 -504
  41. package/dist/components/Tabs.svelte +246 -246
  42. package/dist/components/Tag.svelte +40 -40
  43. package/dist/components/TextArea.svelte +272 -272
  44. package/dist/components/TextField.svelte +396 -256
  45. package/dist/components/TextField.svelte.d.ts +16 -1
  46. package/dist/components/Timeline.svelte +156 -156
  47. package/dist/components/Toaster.svelte +411 -411
  48. package/dist/components/Tooltip.svelte +200 -200
  49. package/dist/components/TooltipGroup.svelte +46 -46
  50. package/dist/components/internal/Scrim.svelte +52 -52
  51. package/dist/components/internal/Sheet.svelte +263 -263
  52. package/dist/fonts.css +71 -71
  53. package/dist/tokens.css +283 -283
  54. package/package.json +81 -76
@@ -5,7 +5,10 @@ export type TextFieldType = 'text' | 'email' | 'password' | 'search' | 'tel' | '
5
5
  export type TextFieldBreakpoint = 'medium' | 'expanded' | 'large';
6
6
  /** Attributes and handlers not listed here go to the `<input>`. */
7
7
  export type TextFieldProps = Omit<HTMLInputAttributes, 'type' | 'value' | 'children'> & {
8
- /** The caps field label above the well. Required: a placeholder is never the only label. */
8
+ /**
9
+ * The caps field label above the well. Required, also with
10
+ * `labelHidden`: a placeholder is never the only label.
11
+ */
9
12
  label: string;
10
13
  /** The text. Bindable. */
11
14
  value?: string;
@@ -24,6 +27,18 @@ export type TextFieldProps = Omit<HTMLInputAttributes, 'type' | 'value' | 'child
24
27
  * The hint and the error stay under the well.
25
28
  */
26
29
  labelBeside?: boolean | TextFieldBreakpoint;
30
+ /**
31
+ * Hides the label from sight; it stays the field's accessible name.
32
+ * For a field whose purpose its place makes plain, such as a search in
33
+ * a toolbar. The well keeps its look and its 16 px text. It overrides
34
+ * `labelBeside`.
35
+ */
36
+ labelHidden?: boolean;
37
+ /**
38
+ * The accessible name of the clear button that `type="search"` shows
39
+ * inside the well while it holds text.
40
+ */
41
+ clearLabel?: string;
27
42
  /** The `<input>`, for example to focus the first error on submit. */
28
43
  ref?: HTMLInputElement | null;
29
44
  };
@@ -1,156 +1,156 @@
1
- <script lang="ts" module>
2
- import type { HTMLOlAttributes } from 'svelte/elements';
3
-
4
- /** A status hue for an event's node: `ok` done, `warn` waiting or needs you, `danger` failed. */
5
- export type TimelineTone = 'ok' | 'warn' | 'danger';
6
-
7
- export type TimelineEvent = {
8
- /** What happened, as the app or a user wrote it. */
9
- title: string;
10
- /** A supporting line in `--muted`. */
11
- detail?: string;
12
- /** The date as shown. */
13
- date: string;
14
- /** The time as shown, after the date. */
15
- time?: string;
16
- /**
17
- * The machine-readable moment for `<time datetime>`. Defaults to
18
- * `date`, or `dateTtime` with a time, so ISO dates need nothing else.
19
- */
20
- datetime?: string;
21
- /**
22
- * Colours the node in a status hue. The title must say the same, because
23
- * colour is never the only signal.
24
- */
25
- tone?: TimelineTone;
26
- };
27
-
28
- export type TimelineProps = Omit<HTMLOlAttributes, 'children'> & {
29
- /** Oldest first or newest first, in the order given. */
30
- events: TimelineEvent[];
31
- };
32
- </script>
33
-
34
- <script lang="ts">
35
- import { onMount, untrack } from 'svelte';
36
- import { useMotion } from '../motion/index.js';
37
-
38
- let { events, class: className, ...rest }: TimelineProps = $props();
39
-
40
- // Expressive stagger (motion rule 7), as in Table: only the events of the
41
- // first render enter, by their index. Each <li> carries its node and its
42
- // rail segment, so they enter with it. Any change to `events` (a new array
43
- // or a changed length) ends the entrance, and so does its last animation.
44
- const motion = useMotion();
45
- const firstEvents = untrack(() => events);
46
- const firstCount = untrack(() => events.length);
47
- let entering = $state.raw(motion.expressive);
48
- let root: HTMLOListElement;
49
-
50
- $effect.pre(() => {
51
- if (events !== firstEvents || events.length !== firstCount) entering = false;
52
- });
53
-
54
- onMount(() => {
55
- if (!entering) return;
56
- const running = root
57
- .getAnimations({ subtree: true })
58
- .filter((a) => a instanceof CSSAnimation && a.animationName === 'hp-enter');
59
- Promise.allSettled(running.map((a) => a.finished)).then(() => {
60
- entering = false;
61
- });
62
- });
63
- </script>
64
-
65
- <!--
66
- Square nodes on a 2px titanium rail (BRIEF, visual rule 7; da3-60), in
67
- Geist Mono. Extra attributes and `class` go to the <ol>.
68
- -->
69
- <ol {...rest} bind:this={root} class={['hp-timeline', className]}>
70
- {#each events as event, i}
71
- <li data-tone={event.tone} class={[entering && 'hp-enter']} style:--i={entering ? i : undefined}>
72
- <span>{event.title}</span>
73
- {#if event.detail}
74
- <span class="detail">{event.detail}</span>
75
- {/if}
76
- <span class="when"
77
- ><time datetime={event.datetime ?? (event.time ? `${event.date}T${event.time}` : event.date)}
78
- >{event.date}</time
79
- >{#if event.time}<span>{event.time}</span>{/if}</span
80
- >
81
- </li>
82
- {/each}
83
- </ol>
84
-
85
- <style>
86
- /* 16px on touch, the dense 14px on fine pointers. A long identifier or
87
- path breaks anywhere rather than widen the page. */
88
- .hp-timeline {
89
- margin: 0;
90
- padding: 0 0 0 var(--space-8);
91
- font-family: var(--mono);
92
- font-size: var(--type-body);
93
- line-height: 24px;
94
- list-style: none;
95
- overflow-wrap: anywhere;
96
- }
97
- @media (pointer: fine) {
98
- .hp-timeline {
99
- font-size: var(--type-dense);
100
- line-height: 20px;
101
- }
102
- }
103
-
104
- li {
105
- position: relative;
106
- display: grid;
107
- padding-bottom: var(--space-6);
108
- }
109
- li:last-child {
110
- padding-bottom: 0;
111
- }
112
-
113
- /* The node: a 12px square, titanium or the event's status hue, centred on
114
- the first line (4px from the top at 20px lines, 6px at 24px). */
115
- li::before {
116
- content: '';
117
- position: absolute;
118
- top: calc((1lh - 12px) / 2);
119
- left: calc(-1 * var(--space-8));
120
- width: 12px;
121
- height: 12px;
122
- background: var(--accent);
123
- }
124
- li[data-tone='ok']::before {
125
- background: var(--ok);
126
- }
127
- li[data-tone='warn']::before {
128
- background: var(--warn);
129
- }
130
- li[data-tone='danger']::before {
131
- background: var(--danger);
132
- }
133
-
134
- /* The rail: 2px, centred under the node, from its bottom edge down to the
135
- next node's top edge. */
136
- li:not(:last-child)::after {
137
- content: '';
138
- position: absolute;
139
- top: calc((1lh + 12px) / 2);
140
- bottom: calc((12px - 1lh) / 2);
141
- /* matches the approved specimen */
142
- left: calc(-1 * var(--space-8) + 5px);
143
- /* matches the approved specimen */
144
- width: 2px;
145
- background: var(--accent);
146
- }
147
-
148
- .detail {
149
- color: var(--muted);
150
- }
151
- .when {
152
- display: flex;
153
- /* matches the approved specimen */
154
- gap: 4ch;
155
- }
156
- </style>
1
+ <script lang="ts" module>
2
+ import type { HTMLOlAttributes } from 'svelte/elements';
3
+
4
+ /** A status hue for an event's node: `ok` done, `warn` waiting or needs you, `danger` failed. */
5
+ export type TimelineTone = 'ok' | 'warn' | 'danger';
6
+
7
+ export type TimelineEvent = {
8
+ /** What happened, as the app or a user wrote it. */
9
+ title: string;
10
+ /** A supporting line in `--muted`. */
11
+ detail?: string;
12
+ /** The date as shown. */
13
+ date: string;
14
+ /** The time as shown, after the date. */
15
+ time?: string;
16
+ /**
17
+ * The machine-readable moment for `<time datetime>`. Defaults to
18
+ * `date`, or `dateTtime` with a time, so ISO dates need nothing else.
19
+ */
20
+ datetime?: string;
21
+ /**
22
+ * Colours the node in a status hue. The title must say the same, because
23
+ * colour is never the only signal.
24
+ */
25
+ tone?: TimelineTone;
26
+ };
27
+
28
+ export type TimelineProps = Omit<HTMLOlAttributes, 'children'> & {
29
+ /** Oldest first or newest first, in the order given. */
30
+ events: TimelineEvent[];
31
+ };
32
+ </script>
33
+
34
+ <script lang="ts">
35
+ import { onMount, untrack } from 'svelte';
36
+ import { useMotion } from '../motion/index.js';
37
+
38
+ let { events, class: className, ...rest }: TimelineProps = $props();
39
+
40
+ // Expressive stagger (motion rule 7), as in Table: only the events of the
41
+ // first render enter, by their index. Each <li> carries its node and its
42
+ // rail segment, so they enter with it. Any change to `events` (a new array
43
+ // or a changed length) ends the entrance, and so does its last animation.
44
+ const motion = useMotion();
45
+ const firstEvents = untrack(() => events);
46
+ const firstCount = untrack(() => events.length);
47
+ let entering = $state.raw(motion.expressive);
48
+ let root: HTMLOListElement;
49
+
50
+ $effect.pre(() => {
51
+ if (events !== firstEvents || events.length !== firstCount) entering = false;
52
+ });
53
+
54
+ onMount(() => {
55
+ if (!entering) return;
56
+ const running = root
57
+ .getAnimations({ subtree: true })
58
+ .filter((a) => a instanceof CSSAnimation && a.animationName === 'hp-enter');
59
+ Promise.allSettled(running.map((a) => a.finished)).then(() => {
60
+ entering = false;
61
+ });
62
+ });
63
+ </script>
64
+
65
+ <!--
66
+ Square nodes on a 2px titanium rail (BRIEF, visual rule 7; da3-60), in
67
+ Geist Mono. Extra attributes and `class` go to the <ol>.
68
+ -->
69
+ <ol {...rest} bind:this={root} class={['hp-timeline', className]}>
70
+ {#each events as event, i}
71
+ <li data-tone={event.tone} class={[entering && 'hp-enter']} style:--i={entering ? i : undefined}>
72
+ <span>{event.title}</span>
73
+ {#if event.detail}
74
+ <span class="detail">{event.detail}</span>
75
+ {/if}
76
+ <span class="when"
77
+ ><time datetime={event.datetime ?? (event.time ? `${event.date}T${event.time}` : event.date)}
78
+ >{event.date}</time
79
+ >{#if event.time}<span>{event.time}</span>{/if}</span
80
+ >
81
+ </li>
82
+ {/each}
83
+ </ol>
84
+
85
+ <style>
86
+ /* 16px on touch, the dense 14px on fine pointers. A long identifier or
87
+ path breaks anywhere rather than widen the page. */
88
+ .hp-timeline {
89
+ margin: 0;
90
+ padding: 0 0 0 var(--space-8);
91
+ font-family: var(--mono);
92
+ font-size: var(--type-body);
93
+ line-height: 24px;
94
+ list-style: none;
95
+ overflow-wrap: anywhere;
96
+ }
97
+ @media (pointer: fine) {
98
+ .hp-timeline {
99
+ font-size: var(--type-dense);
100
+ line-height: 20px;
101
+ }
102
+ }
103
+
104
+ li {
105
+ position: relative;
106
+ display: grid;
107
+ padding-bottom: var(--space-6);
108
+ }
109
+ li:last-child {
110
+ padding-bottom: 0;
111
+ }
112
+
113
+ /* The node: a 12px square, titanium or the event's status hue, centred on
114
+ the first line (4px from the top at 20px lines, 6px at 24px). */
115
+ li::before {
116
+ content: '';
117
+ position: absolute;
118
+ top: calc((1lh - 12px) / 2);
119
+ left: calc(-1 * var(--space-8));
120
+ width: 12px;
121
+ height: 12px;
122
+ background: var(--accent);
123
+ }
124
+ li[data-tone='ok']::before {
125
+ background: var(--ok);
126
+ }
127
+ li[data-tone='warn']::before {
128
+ background: var(--warn);
129
+ }
130
+ li[data-tone='danger']::before {
131
+ background: var(--danger);
132
+ }
133
+
134
+ /* The rail: 2px, centred under the node, from its bottom edge down to the
135
+ next node's top edge. */
136
+ li:not(:last-child)::after {
137
+ content: '';
138
+ position: absolute;
139
+ top: calc((1lh + 12px) / 2);
140
+ bottom: calc((12px - 1lh) / 2);
141
+ /* matches the approved specimen */
142
+ left: calc(-1 * var(--space-8) + 5px);
143
+ /* matches the approved specimen */
144
+ width: 2px;
145
+ background: var(--accent);
146
+ }
147
+
148
+ .detail {
149
+ color: var(--muted);
150
+ }
151
+ .when {
152
+ display: flex;
153
+ /* matches the approved specimen */
154
+ gap: 4ch;
155
+ }
156
+ </style>