@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
@@ -1,222 +1,222 @@
1
- <script lang="ts" module>
2
- import { Switch as BitsSwitch } from 'bits-ui';
3
-
4
- /** Attributes and handlers not listed here go to the switch button. */
5
- export type SwitchProps = Omit<BitsSwitch.RootProps, 'child' | 'children' | 'ref'> & {
6
- /**
7
- * The setting's name, as written (never caps), at the start of the line;
8
- * the switch sits at its end. Pressing anywhere on the label turns the
9
- * switch on or off. Without it, give the switch an accessible name with
10
- * `aria-label`.
11
- */
12
- label?: string;
13
- /** A second line in `--muted` under the label, read out as the switch's description. */
14
- hint?: string;
15
- /** The switch button. */
16
- ref?: HTMLElement | null;
17
- };
18
- </script>
19
-
20
- <script lang="ts">
21
- const uid = $props.id();
22
-
23
- let {
24
- checked = $bindable(false),
25
- label,
26
- hint,
27
- id = uid,
28
- ref = $bindable(null),
29
- class: className,
30
- 'aria-describedby': describedBy,
31
- ...rest
32
- }: SwitchProps = $props();
33
-
34
- const hintId = $derived(`${id}-hint`);
35
- const describedByIds = $derived([hint ? hintId : null, describedBy].filter(Boolean).join(' ') || undefined);
36
- </script>
37
-
38
- <!--
39
- A Bits UI Switch: a <button role="switch"> with aria-checked, its state in
40
- data-state (checked, unchecked) and data-disabled. An on/off setting that
41
- applies at once, as omp-remote's settings rows: the label, the switch at
42
- the end of its line, then the hint. Attributes, handlers and `class` go to
43
- the button.
44
- -->
45
- <div class="hp-switch">
46
- {#if label}
47
- <label class="hp-dense" for={id}>{label}</label>
48
- {/if}
49
- <span class="control">
50
- <BitsSwitch.Root bind:checked bind:ref {id} aria-describedby={describedByIds} {...rest}>
51
- {#snippet child({ props })}
52
- <button {...props} class={['track', className]}>
53
- <BitsSwitch.Thumb>
54
- {#snippet child({ props: thumbProps })}
55
- <span {...thumbProps} class="thumb"></span>
56
- {/snippet}
57
- </BitsSwitch.Thumb>
58
- </button>
59
- {/snippet}
60
- </BitsSwitch.Root>
61
- </span>
62
- {#if hint}
63
- <p class="hint hp-caption" id={hintId}>{hint}</p>
64
- {/if}
65
- </div>
66
-
67
- <style>
68
- /* The label fills the line and the switch sits at its end. The first
69
- line is one hit-target band (24px fine, 44px coarse): the switch sits
70
- centred in it and the label's first line too, so the whole label line
71
- is a target. The hint runs under the label. Without a label the root
72
- is as wide as the switch. */
73
- .hp-switch {
74
- /* The label's line height, as .hp-dense sets it. */
75
- --_line: 24px;
76
- display: grid;
77
- grid-template-columns: auto;
78
- justify-content: start;
79
- align-items: start;
80
- }
81
- .hp-switch:has(> label) {
82
- grid-template-columns: minmax(0, 1fr) auto;
83
- column-gap: var(--space-4);
84
- }
85
- @media (pointer: fine) {
86
- .hp-switch {
87
- --_line: 20px;
88
- }
89
- }
90
-
91
- label {
92
- padding: calc((var(--hit-target) - var(--_line)) / 2) 0;
93
- cursor: pointer;
94
- -webkit-tap-highlight-color: transparent;
95
- }
96
-
97
- .control {
98
- position: relative;
99
- grid-column: -2;
100
- grid-row: 1;
101
- display: flex;
102
- align-items: center;
103
- height: var(--hit-target);
104
- }
105
-
106
- /* A black box with a 3:1 boundary and a square thumb. On, the edge and the
107
- thumb turn titanium and the thumb shows at the end; the box stays black,
108
- because selection is never a fill. Focus is base.css's contour 4px
109
- outside, so it never looks like the on edge. */
110
- .track {
111
- position: relative;
112
- display: block;
113
- box-sizing: border-box;
114
- width: 40px;
115
- height: 24px;
116
- margin: 0;
117
- padding: 0;
118
- border: 1px solid var(--border-control);
119
- background: var(--canvas);
120
- cursor: pointer;
121
- -webkit-tap-highlight-color: transparent;
122
- }
123
- /* The hit area: at least --hit-target square, centred on the track. */
124
- .track::before {
125
- content: '';
126
- position: absolute;
127
- top: 50%;
128
- left: 50%;
129
- width: max(100%, var(--hit-target));
130
- height: max(100%, var(--hit-target));
131
- translate: -50% -50%;
132
- }
133
- .track[data-state='checked'] {
134
- border-color: var(--accent);
135
- }
136
-
137
- /* The thumb: two 16px squares, 4px in from the outer edge (inside the
138
- 1px border), ::before at the start (off) and ::after at the end (on).
139
- Each is at opacity 0 until its state comes. The one a change brings
140
- fades in from 0 at its place over --dur-mark (BRIEF, short motion) and
141
- the other goes at once, so the thumb never slides. A CSS transition
142
- never runs on an element's first style, so a switch shows its state at
143
- once when it renders. 0ms is a snap. Opacity only: nothing moves, so
144
- reduced motion keeps it. */
145
- .thumb {
146
- position: absolute;
147
- top: calc(var(--space-1) - 1px);
148
- left: calc(var(--space-1) - 1px);
149
- width: 16px;
150
- height: 16px;
151
- }
152
- .thumb::before,
153
- .thumb::after {
154
- content: '';
155
- position: absolute;
156
- top: 0;
157
- width: 16px;
158
- height: 16px;
159
- opacity: 0;
160
- }
161
- .thumb::before {
162
- left: 0;
163
- background: var(--muted);
164
- }
165
- .thumb::after {
166
- left: 16px;
167
- background: var(--accent);
168
- }
169
- .track[data-state='unchecked'] .thumb::before,
170
- .track[data-state='checked'] .thumb::after {
171
- opacity: 1;
172
- transition: opacity var(--dur-mark) var(--settle);
173
- }
174
-
175
- .hint {
176
- grid-column: 1;
177
- color: var(--muted);
178
- }
179
-
180
- /* ---- Hover: fine pointers only, over the switch or its label ------- */
181
-
182
- @media (hover: hover) and (pointer: fine) {
183
- .track {
184
- transition:
185
- background-color var(--dur-hover) var(--settle),
186
- border-color var(--dur-hover) var(--settle);
187
- }
188
- .hp-switch:has(> label:hover, .track:hover) .track:not(:disabled) {
189
- background-color: var(--surface-hover);
190
- }
191
- .hp-switch:has(> label:hover, .track:hover) .track[data-state='unchecked']:not(:disabled) {
192
- border-color: var(--muted);
193
- }
194
- .hp-switch:has(> label:active, .track:active) .track:not(:disabled) {
195
- transition-duration: var(--dur-press);
196
- }
197
- }
198
-
199
- /* ---- Press: one step past hover, so it reads on a phone too -------- */
200
-
201
- .hp-switch:has(> label:active, .track:active) .track:not(:disabled) {
202
- background-color: var(--surface-raised);
203
- }
204
-
205
- /* ---- Disabled: the quieter --border and a --border thumb, as
206
- omp-remote's; on keeps its place at the end ------------------------ */
207
-
208
- .track:disabled {
209
- border-color: var(--border);
210
- cursor: not-allowed;
211
- }
212
- .track:disabled .thumb::before {
213
- background: var(--border);
214
- }
215
- .track:disabled .thumb::after {
216
- background: var(--muted);
217
- }
218
- .hp-switch:has(.track:disabled) label {
219
- color: var(--muted);
220
- cursor: not-allowed;
221
- }
222
- </style>
1
+ <script lang="ts" module>
2
+ import { Switch as BitsSwitch } from 'bits-ui';
3
+
4
+ /** Attributes and handlers not listed here go to the switch button. */
5
+ export type SwitchProps = Omit<BitsSwitch.RootProps, 'child' | 'children' | 'ref'> & {
6
+ /**
7
+ * The setting's name, as written (never caps), at the start of the line;
8
+ * the switch sits at its end. Pressing anywhere on the label turns the
9
+ * switch on or off. Without it, give the switch an accessible name with
10
+ * `aria-label`.
11
+ */
12
+ label?: string;
13
+ /** A second line in `--muted` under the label, read out as the switch's description. */
14
+ hint?: string;
15
+ /** The switch button. */
16
+ ref?: HTMLElement | null;
17
+ };
18
+ </script>
19
+
20
+ <script lang="ts">
21
+ const uid = $props.id();
22
+
23
+ let {
24
+ checked = $bindable(false),
25
+ label,
26
+ hint,
27
+ id = uid,
28
+ ref = $bindable(null),
29
+ class: className,
30
+ 'aria-describedby': describedBy,
31
+ ...rest
32
+ }: SwitchProps = $props();
33
+
34
+ const hintId = $derived(`${id}-hint`);
35
+ const describedByIds = $derived([hint ? hintId : null, describedBy].filter(Boolean).join(' ') || undefined);
36
+ </script>
37
+
38
+ <!--
39
+ A Bits UI Switch: a <button role="switch"> with aria-checked, its state in
40
+ data-state (checked, unchecked) and data-disabled. An on/off setting that
41
+ applies at once, as omp-remote's settings rows: the label, the switch at
42
+ the end of its line, then the hint. Attributes, handlers and `class` go to
43
+ the button.
44
+ -->
45
+ <div class="hp-switch">
46
+ {#if label}
47
+ <label class="hp-dense" for={id}>{label}</label>
48
+ {/if}
49
+ <span class="control">
50
+ <BitsSwitch.Root bind:checked bind:ref {id} aria-describedby={describedByIds} {...rest}>
51
+ {#snippet child({ props })}
52
+ <button {...props} class={['track', className]}>
53
+ <BitsSwitch.Thumb>
54
+ {#snippet child({ props: thumbProps })}
55
+ <span {...thumbProps} class="thumb"></span>
56
+ {/snippet}
57
+ </BitsSwitch.Thumb>
58
+ </button>
59
+ {/snippet}
60
+ </BitsSwitch.Root>
61
+ </span>
62
+ {#if hint}
63
+ <p class="hint hp-caption" id={hintId}>{hint}</p>
64
+ {/if}
65
+ </div>
66
+
67
+ <style>
68
+ /* The label fills the line and the switch sits at its end. The first
69
+ line is one hit-target band (24px fine, 44px coarse): the switch sits
70
+ centred in it and the label's first line too, so the whole label line
71
+ is a target. The hint runs under the label. Without a label the root
72
+ is as wide as the switch. */
73
+ .hp-switch {
74
+ /* The label's line height, as .hp-dense sets it. */
75
+ --_line: 24px;
76
+ display: grid;
77
+ grid-template-columns: auto;
78
+ justify-content: start;
79
+ align-items: start;
80
+ }
81
+ .hp-switch:has(> label) {
82
+ grid-template-columns: minmax(0, 1fr) auto;
83
+ column-gap: var(--space-4);
84
+ }
85
+ @media (pointer: fine) {
86
+ .hp-switch {
87
+ --_line: 20px;
88
+ }
89
+ }
90
+
91
+ label {
92
+ padding: calc((var(--hit-target) - var(--_line)) / 2) 0;
93
+ cursor: pointer;
94
+ -webkit-tap-highlight-color: transparent;
95
+ }
96
+
97
+ .control {
98
+ position: relative;
99
+ grid-column: -2;
100
+ grid-row: 1;
101
+ display: flex;
102
+ align-items: center;
103
+ height: var(--hit-target);
104
+ }
105
+
106
+ /* A black box with a 3:1 boundary and a square thumb. On, the edge and the
107
+ thumb turn titanium and the thumb shows at the end; the box stays black,
108
+ because selection is never a fill. Focus is base.css's contour 4px
109
+ outside, so it never looks like the on edge. */
110
+ .track {
111
+ position: relative;
112
+ display: block;
113
+ box-sizing: border-box;
114
+ width: 40px;
115
+ height: 24px;
116
+ margin: 0;
117
+ padding: 0;
118
+ border: 1px solid var(--border-control);
119
+ background: var(--canvas);
120
+ cursor: pointer;
121
+ -webkit-tap-highlight-color: transparent;
122
+ }
123
+ /* The hit area: at least --hit-target square, centred on the track. */
124
+ .track::before {
125
+ content: '';
126
+ position: absolute;
127
+ top: 50%;
128
+ left: 50%;
129
+ width: max(100%, var(--hit-target));
130
+ height: max(100%, var(--hit-target));
131
+ translate: -50% -50%;
132
+ }
133
+ .track[data-state='checked'] {
134
+ border-color: var(--accent);
135
+ }
136
+
137
+ /* The thumb: two 16px squares, 4px in from the outer edge (inside the
138
+ 1px border), ::before at the start (off) and ::after at the end (on).
139
+ Each is at opacity 0 until its state comes. The one a change brings
140
+ fades in from 0 at its place over --dur-mark (BRIEF, short motion) and
141
+ the other goes at once, so the thumb never slides. A CSS transition
142
+ never runs on an element's first style, so a switch shows its state at
143
+ once when it renders. 0ms is a snap. Opacity only: nothing moves, so
144
+ reduced motion keeps it. */
145
+ .thumb {
146
+ position: absolute;
147
+ top: calc(var(--space-1) - 1px);
148
+ left: calc(var(--space-1) - 1px);
149
+ width: 16px;
150
+ height: 16px;
151
+ }
152
+ .thumb::before,
153
+ .thumb::after {
154
+ content: '';
155
+ position: absolute;
156
+ top: 0;
157
+ width: 16px;
158
+ height: 16px;
159
+ opacity: 0;
160
+ }
161
+ .thumb::before {
162
+ left: 0;
163
+ background: var(--muted);
164
+ }
165
+ .thumb::after {
166
+ left: 16px;
167
+ background: var(--accent);
168
+ }
169
+ .track[data-state='unchecked'] .thumb::before,
170
+ .track[data-state='checked'] .thumb::after {
171
+ opacity: 1;
172
+ transition: opacity var(--dur-mark) var(--settle);
173
+ }
174
+
175
+ .hint {
176
+ grid-column: 1;
177
+ color: var(--muted);
178
+ }
179
+
180
+ /* ---- Hover: fine pointers only, over the switch or its label ------- */
181
+
182
+ @media (hover: hover) and (pointer: fine) {
183
+ .track {
184
+ transition:
185
+ background-color var(--dur-hover) var(--settle),
186
+ border-color var(--dur-hover) var(--settle);
187
+ }
188
+ .hp-switch:has(> label:hover, .track:hover) .track:not(:disabled) {
189
+ background-color: var(--surface-hover);
190
+ }
191
+ .hp-switch:has(> label:hover, .track:hover) .track[data-state='unchecked']:not(:disabled) {
192
+ border-color: var(--muted);
193
+ }
194
+ .hp-switch:has(> label:active, .track:active) .track:not(:disabled) {
195
+ transition-duration: var(--dur-press);
196
+ }
197
+ }
198
+
199
+ /* ---- Press: one step past hover, so it reads on a phone too -------- */
200
+
201
+ .hp-switch:has(> label:active, .track:active) .track:not(:disabled) {
202
+ background-color: var(--surface-raised);
203
+ }
204
+
205
+ /* ---- Disabled: the quieter --border and a --border thumb, as
206
+ omp-remote's; on keeps its place at the end ------------------------ */
207
+
208
+ .track:disabled {
209
+ border-color: var(--border);
210
+ cursor: not-allowed;
211
+ }
212
+ .track:disabled .thumb::before {
213
+ background: var(--border);
214
+ }
215
+ .track:disabled .thumb::after {
216
+ background: var(--muted);
217
+ }
218
+ .hp-switch:has(.track:disabled) label {
219
+ color: var(--muted);
220
+ cursor: not-allowed;
221
+ }
222
+ </style>