@skewedaspect/sleekspace-ui 0.8.1 → 0.9.1
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.
- package/dist/components/Dropdown/SkDropdown.vue.d.ts +9 -1
- package/dist/components/Dropdown/types.d.ts +2 -1
- package/dist/components/NavBar/SkNavBar.vue.d.ts +9 -1
- package/dist/components/NavBar/context.d.ts +2 -0
- package/dist/components/NavBar/types.d.ts +5 -1
- package/dist/components/NumberInput/SkNumberInput.vue.d.ts +8 -0
- package/dist/components/Page/SkPage.vue.d.ts +9 -0
- package/dist/components/ScrollArea/SkScrollArea.vue.d.ts +105 -4
- package/dist/composables/useCustomColors.d.ts +18 -56
- package/{src → dist}/global.d.ts +6 -2
- package/dist/sleekspace-ui.css +4257 -1253
- package/dist/sleekspace-ui.es.js +300 -170
- package/dist/sleekspace-ui.umd.js +299 -169
- package/dist/static/classes.d.ts +18 -0
- package/dist/static/components/alert.d.ts +12 -0
- package/dist/static/components/avatar.d.ts +9 -0
- package/dist/static/components/breadcrumbs.d.ts +6 -0
- package/dist/static/components/button.d.ts +13 -0
- package/dist/static/components/card.d.ts +5 -0
- package/dist/static/components/checkbox.d.ts +10 -0
- package/dist/static/components/colorPicker.d.ts +8 -0
- package/dist/static/components/divider.d.ts +8 -0
- package/dist/static/components/dropdown.d.ts +8 -0
- package/dist/static/components/field.d.ts +15 -0
- package/dist/static/components/group.d.ts +5 -0
- package/dist/static/components/input.d.ts +14 -0
- package/dist/static/components/navBar.d.ts +16 -0
- package/dist/static/components/numberInput.d.ts +15 -0
- package/dist/static/components/page.d.ts +9 -0
- package/dist/static/components/pagination.d.ts +5 -0
- package/dist/static/components/panel.d.ts +11 -0
- package/dist/static/components/progress.d.ts +9 -0
- package/dist/static/components/radio.d.ts +11 -0
- package/dist/static/components/select.d.ts +10 -0
- package/dist/static/components/sidebar.d.ts +9 -0
- package/dist/static/components/skeleton.d.ts +11 -0
- package/dist/static/components/slider.d.ts +12 -0
- package/dist/static/components/spinner.d.ts +12 -0
- package/dist/static/components/switchInput.d.ts +10 -0
- package/dist/static/components/table.d.ts +12 -0
- package/dist/static/components/tag.d.ts +8 -0
- package/dist/static/components/tagsInput.d.ts +7 -0
- package/dist/static/components/textarea.d.ts +12 -0
- package/dist/static/components/toolbar.d.ts +12 -0
- package/dist/static/components/tooltip.d.ts +7 -0
- package/dist/static/escape.d.ts +2 -0
- package/dist/static/index.cjs.js +1 -0
- package/dist/static/index.d.ts +68 -0
- package/dist/static/index.es.js +732 -0
- package/dist/static/render.d.ts +12 -0
- package/dist/static/specs.d.ts +2 -0
- package/dist/static/types.d.ts +43 -0
- package/dist/tokens.css +322 -0
- package/dist/types/index.d.ts +36 -0
- package/dist/utils/slots.d.ts +6 -0
- package/docs/guides/installation.md +8 -2
- package/docs/guides/pure-css/_meta.yaml +8 -0
- package/docs/guides/pure-css/class-api.md +1070 -0
- package/docs/guides/pure-css/custom-elements.md +574 -0
- package/docs/guides/pure-css/index.md +86 -0
- package/docs/guides/pure-css/limitations.md +152 -0
- package/docs/guides/pure-css/static-helpers.md +1203 -0
- package/llms-full.txt +3739 -261
- package/package.json +19 -5
- package/src/components/Alert/SkAlert.vue +4 -2
- package/src/components/Breadcrumbs/SkBreadcrumbs.vue +6 -12
- package/src/components/Button/SkButton.vue +8 -5
- package/src/components/Card/SkCard.vue +13 -5
- package/src/components/Checkbox/SkCheckbox.vue +9 -2
- package/src/components/ContextMenu/SkContextMenuRadioGroup.vue +4 -1
- package/src/components/Dropdown/SkDropdown.vue +20 -3
- package/src/components/Dropdown/SkDropdownRadioGroup.vue +4 -1
- package/src/components/Dropdown/types.ts +2 -1
- package/src/components/Modal/SkModal.vue +11 -4
- package/src/components/NavBar/SkNavBar.vue +19 -8
- package/src/components/NavBar/context.ts +4 -2
- package/src/components/NavBar/types.ts +6 -1
- package/src/components/NumberInput/SkNumberInput.vue +10 -1
- package/src/components/Page/SkPage.vue +29 -15
- package/src/components/Panel/SkPanel.vue +2 -1
- package/src/components/Popover/SkPopover.vue +11 -4
- package/src/components/Radio/SkRadio.vue +9 -2
- package/src/components/ScrollArea/SkScrollArea.vue +78 -5
- package/src/components/Switch/SkSwitch.vue +14 -13
- package/src/components/Tabs/SkTab.vue +7 -2
- package/src/components/TreeView/SkTreeItem.vue +10 -2
- package/src/components/TreeView/SkTreeView.vue +7 -2
- package/src/composables/useCustomColors.ts +86 -77
- package/src/composables/usePortalContext.test.ts +0 -2
- package/src/shims.d.ts +10 -0
- package/src/static/__tests__/parity.test.ts +717 -0
- package/src/static/__tests__/parityHarness.test.ts +98 -0
- package/src/static/__tests__/parityHarness.ts +260 -0
- package/src/static/classes.test.ts +82 -0
- package/src/static/classes.ts +111 -0
- package/src/static/components/__tests__/helpers.test.ts +837 -0
- package/src/static/components/alert.ts +117 -0
- package/src/static/components/avatar.ts +86 -0
- package/src/static/components/breadcrumbs.ts +28 -0
- package/src/static/components/button.ts +75 -0
- package/src/static/components/card.ts +27 -0
- package/src/static/components/checkbox.ts +48 -0
- package/src/static/components/colorPicker.ts +45 -0
- package/src/static/components/divider.ts +39 -0
- package/src/static/components/dropdown.ts +36 -0
- package/src/static/components/field.ts +86 -0
- package/src/static/components/group.ts +27 -0
- package/src/static/components/input.ts +55 -0
- package/src/static/components/navBar.ts +94 -0
- package/src/static/components/numberInput.ts +64 -0
- package/src/static/components/page.ts +31 -0
- package/src/static/components/pagination.ts +27 -0
- package/src/static/components/panel.ts +33 -0
- package/src/static/components/progress.ts +31 -0
- package/src/static/components/radio.ts +53 -0
- package/src/static/components/select.ts +51 -0
- package/src/static/components/sidebar.ts +85 -0
- package/src/static/components/skeleton.ts +66 -0
- package/src/static/components/slider.ts +50 -0
- package/src/static/components/spinner.ts +94 -0
- package/src/static/components/switchInput.ts +49 -0
- package/src/static/components/table.ts +88 -0
- package/src/static/components/tag.ts +76 -0
- package/src/static/components/tagsInput.ts +35 -0
- package/src/static/components/textarea.ts +53 -0
- package/src/static/components/toolbar.ts +74 -0
- package/src/static/components/tooltip.ts +29 -0
- package/src/static/escape.test.ts +53 -0
- package/src/static/escape.ts +28 -0
- package/src/static/generated/defaults.ts +379 -0
- package/src/static/generated/propTypes.ts +426 -0
- package/src/static/index.ts +116 -0
- package/src/static/render.test.ts +83 -0
- package/src/static/render.ts +76 -0
- package/src/static/specs.test.ts +58 -0
- package/src/static/specs.ts +230 -0
- package/src/static/types.ts +176 -0
- package/src/styles/__tests__/testHelpers.ts +97 -0
- package/src/styles/base/_custom-elements.scss +51 -0
- package/src/styles/base/_index.scss +4 -0
- package/src/styles/components/__tests__/componentSelectors.test.ts +2575 -0
- package/src/styles/components/_alert.scss +82 -39
- package/src/styles/components/_avatar.scss +102 -47
- package/src/styles/components/_breadcrumbs.scss +39 -37
- package/src/styles/components/_button.scss +58 -5
- package/src/styles/components/_card.scss +64 -2
- package/src/styles/components/_checkbox.scss +35 -5
- package/src/styles/components/_color-picker.scss +48 -13
- package/src/styles/components/_divider.scss +86 -52
- package/src/styles/components/_dropdown.scss +214 -0
- package/src/styles/components/_field.scss +76 -23
- package/src/styles/components/_group.scss +190 -79
- package/src/styles/components/_index.scss +1 -0
- package/src/styles/components/_input.scss +81 -5
- package/src/styles/components/_menu.scss +1 -1
- package/src/styles/components/_navbar.scss +76 -45
- package/src/styles/components/_number-input.scss +98 -85
- package/src/styles/components/_page.scss +82 -23
- package/src/styles/components/_pagination.scss +240 -212
- package/src/styles/components/_panel.scss +268 -122
- package/src/styles/components/_progress.scss +120 -70
- package/src/styles/components/_radio.scss +35 -5
- package/src/styles/components/_scroll-area.scss +50 -22
- package/src/styles/components/_select.scss +40 -9
- package/src/styles/components/_sidebar.scss +59 -34
- package/src/styles/components/_skeleton.scss +111 -65
- package/src/styles/components/_slider.scss +34 -10
- package/src/styles/components/_spinner.scss +107 -56
- package/src/styles/components/_switch.scss +36 -5
- package/src/styles/components/_table.scss +150 -166
- package/src/styles/components/_tag.scss +244 -154
- package/src/styles/components/_tags-input.scss +46 -12
- package/src/styles/components/_textarea.scss +36 -5
- package/src/styles/components/_toolbar.scss +85 -31
- package/src/styles/components/_tooltip.scss +172 -3
- package/src/styles/mixins/_cut-border.scss +18 -4
- package/src/styles/mixins/_dual-selector.scss +192 -0
- package/src/styles/mixins/_index.scss +1 -0
- package/src/styles/mixins/dualSelector.test.ts +151 -0
- package/src/styles/themes/_colorful.scss +25 -0
- package/src/styles/themes/_greyscale.scss +25 -0
- package/src/styles/themes/_shade-scale.scss +39 -0
- package/src/styles/tokens/_semantic-color-kinds.scss +66 -0
- package/src/{types.ts → types/index.ts} +19 -11
- package/src/utils/slots.ts +75 -0
- package/web-types.json +980 -137
- package/dist/composables/useCustomColors.test.d.ts +0 -1
- package/dist/composables/useFocusTrap.test.d.ts +0 -1
- package/dist/composables/usePortalContext.test.d.ts +0 -1
- package/dist/styles/mixins/fluidSize.test.d.ts +0 -1
- package/dist/types.d.ts +0 -29
|
@@ -0,0 +1,151 @@
|
|
|
1
|
+
//----------------------------------------------------------------------------------------------------------------------
|
|
2
|
+
// Dual-Selector Mixin Tests
|
|
3
|
+
//
|
|
4
|
+
// Compiles small SCSS snippets against the `dual-selector` mixins and asserts the emitted
|
|
5
|
+
// selectors contain both class and attribute forms.
|
|
6
|
+
//----------------------------------------------------------------------------------------------------------------------
|
|
7
|
+
|
|
8
|
+
import { describe, expect, it } from 'vitest';
|
|
9
|
+
import { compileString } from 'sass';
|
|
10
|
+
import { dirname } from 'node:path';
|
|
11
|
+
import { fileURLToPath, pathToFileURL } from 'node:url';
|
|
12
|
+
|
|
13
|
+
// Utils
|
|
14
|
+
import { attrValueRe, dualSelectorRe } from '../__tests__/testHelpers';
|
|
15
|
+
|
|
16
|
+
//----------------------------------------------------------------------------------------------------------------------
|
|
17
|
+
|
|
18
|
+
const here = dirname(fileURLToPath(import.meta.url));
|
|
19
|
+
|
|
20
|
+
function emit(snippet : string) : string
|
|
21
|
+
{
|
|
22
|
+
const source = `@use 'dual-selector' as *;\n\n${ snippet }`;
|
|
23
|
+
const { css } = compileString(source, {
|
|
24
|
+
loadPaths: [ here ],
|
|
25
|
+
url: pathToFileURL(`${ here }/dualSelector.test.scss`),
|
|
26
|
+
});
|
|
27
|
+
return css;
|
|
28
|
+
}
|
|
29
|
+
|
|
30
|
+
//----------------------------------------------------------------------------------------------------------------------
|
|
31
|
+
|
|
32
|
+
// Sass strips quotes from attribute-selector values that don't need them for CSS validity,
|
|
33
|
+
// so `[kind="primary"]` is emitted as `[kind=primary]`. `attrValueRe` and `dualSelectorRe`
|
|
34
|
+
// (imported from testHelpers) build regex fragments that accept both forms.
|
|
35
|
+
|
|
36
|
+
describe('dual-selector mixins (SCSS)', () =>
|
|
37
|
+
{
|
|
38
|
+
describe('kind-variant', () =>
|
|
39
|
+
{
|
|
40
|
+
it('emits both .sk-foo.sk-primary and sk-foo[kind=primary]', () =>
|
|
41
|
+
{
|
|
42
|
+
const css = emit(`@include kind-variant('foo', 'primary') { color: red; }`);
|
|
43
|
+
expect(css).toMatch(new RegExp(dualSelectorRe('foo', 'primary', 'kind', 'primary')));
|
|
44
|
+
expect(css).toMatch(/color:\s*red/);
|
|
45
|
+
});
|
|
46
|
+
});
|
|
47
|
+
|
|
48
|
+
describe('size-variant', () =>
|
|
49
|
+
{
|
|
50
|
+
it('emits .sk-foo.sk-lg, .sk-foo.sk-size-lg, and sk-foo[size=lg]', () =>
|
|
51
|
+
{
|
|
52
|
+
const css = emit(`@include size-variant('foo', 'lg') { padding: 2rem; }`);
|
|
53
|
+
expect(css).toMatch(/\.sk-foo\.sk-lg,/);
|
|
54
|
+
expect(css).toMatch(/\.sk-foo\.sk-size-lg,/);
|
|
55
|
+
expect(css).toMatch(new RegExp(`sk-foo\\[size=${ attrValueRe('lg') }\\]`));
|
|
56
|
+
});
|
|
57
|
+
});
|
|
58
|
+
|
|
59
|
+
describe('variant-variant', () =>
|
|
60
|
+
{
|
|
61
|
+
it('emits both .sk-foo.sk-solid and sk-foo[variant=solid]', () =>
|
|
62
|
+
{
|
|
63
|
+
const css = emit(`@include variant-variant('foo', 'solid') { background: blue; }`);
|
|
64
|
+
expect(css).toMatch(new RegExp(dualSelectorRe('foo', 'solid', 'variant', 'solid')));
|
|
65
|
+
});
|
|
66
|
+
});
|
|
67
|
+
|
|
68
|
+
describe('bool-modifier', () =>
|
|
69
|
+
{
|
|
70
|
+
it('emits both .sk-foo.sk-no-border and sk-foo[no-border]', () =>
|
|
71
|
+
{
|
|
72
|
+
const css = emit(`@include bool-modifier('foo', 'no-border') { border: 0; }`);
|
|
73
|
+
expect(css).toMatch(/\.sk-foo\.sk-no-border,\s*sk-foo\[no-border\]/);
|
|
74
|
+
});
|
|
75
|
+
});
|
|
76
|
+
|
|
77
|
+
describe('list-modifier', () =>
|
|
78
|
+
{
|
|
79
|
+
it('emits class + ~= attribute selector for a single list value (explicit $attr)', () =>
|
|
80
|
+
{
|
|
81
|
+
const css = emit(
|
|
82
|
+
`@include list-modifier('foo', 'cut', 'top-left', 'corners') { --cut-tl: 8px; }`
|
|
83
|
+
);
|
|
84
|
+
expect(css).toMatch(new RegExp(
|
|
85
|
+
dualSelectorRe('foo', 'cut-top-left', 'corners', 'top-left', { attrOp: '~=' })
|
|
86
|
+
));
|
|
87
|
+
});
|
|
88
|
+
|
|
89
|
+
it('uses family as attribute name when $attr is omitted', () =>
|
|
90
|
+
{
|
|
91
|
+
const css = emit(`@include list-modifier('foo', 'item', 'alpha') { color: red; }`);
|
|
92
|
+
expect(css).toMatch(new RegExp(
|
|
93
|
+
dualSelectorRe('foo', 'item-alpha', 'item', 'alpha', { attrOp: '~=' })
|
|
94
|
+
));
|
|
95
|
+
});
|
|
96
|
+
});
|
|
97
|
+
|
|
98
|
+
describe('single-choice-modifier', () =>
|
|
99
|
+
{
|
|
100
|
+
it('emits class + exact-match attribute selector (explicit $attr)', () =>
|
|
101
|
+
{
|
|
102
|
+
const css = emit(
|
|
103
|
+
`@include single-choice-modifier('foo', 'orient', 'vertical', 'orientation') { height: 100%; }`
|
|
104
|
+
);
|
|
105
|
+
expect(css).toMatch(new RegExp(
|
|
106
|
+
dualSelectorRe('foo', 'orient-vertical', 'orientation', 'vertical')
|
|
107
|
+
));
|
|
108
|
+
});
|
|
109
|
+
|
|
110
|
+
it('uses family as attribute name when $attr is omitted', () =>
|
|
111
|
+
{
|
|
112
|
+
const css = emit(
|
|
113
|
+
`@include single-choice-modifier('foo', 'mode', 'compact') { padding: 0.5rem; }`
|
|
114
|
+
);
|
|
115
|
+
expect(css).toMatch(new RegExp(dualSelectorRe('foo', 'mode-compact', 'mode', 'compact')));
|
|
116
|
+
});
|
|
117
|
+
});
|
|
118
|
+
|
|
119
|
+
describe('defaults-when-absent', () =>
|
|
120
|
+
{
|
|
121
|
+
it('emits :where(:not([class*=sk-cut-])) selector with zero specificity', () =>
|
|
122
|
+
{
|
|
123
|
+
const css = emit(`@include defaults-when-absent('foo', 'sk-cut-') { --default: 1; }`);
|
|
124
|
+
// Sass may or may not quote the [class*=] value; match both forms.
|
|
125
|
+
expect(css).toMatch(new RegExp(
|
|
126
|
+
`\\.sk-foo:where\\(:not\\(\\[class\\*=${ attrValueRe('sk-cut-') }\\]\\)\\)`
|
|
127
|
+
));
|
|
128
|
+
expect(css).toMatch(/--default:\s*1/);
|
|
129
|
+
});
|
|
130
|
+
});
|
|
131
|
+
|
|
132
|
+
describe('defaults-when-no-attr', () =>
|
|
133
|
+
{
|
|
134
|
+
it('emits sk-<component>:where(:not([<attr>])) selector with zero specificity', () =>
|
|
135
|
+
{
|
|
136
|
+
const css = emit(`@include defaults-when-no-attr('foo', 'kind') { --default: 2; }`);
|
|
137
|
+
expect(css).toMatch(/sk-foo:where\(:not\(\[kind\]\)\)/);
|
|
138
|
+
expect(css).toMatch(/--default:\s*2/);
|
|
139
|
+
});
|
|
140
|
+
|
|
141
|
+
it('works with hyphenated attribute names', () =>
|
|
142
|
+
{
|
|
143
|
+
const css = emit(
|
|
144
|
+
`@include defaults-when-no-attr('panel', 'decoration-corner') { color: red; }`
|
|
145
|
+
);
|
|
146
|
+
expect(css).toMatch(/sk-panel:where\(:not\(\[decoration-corner\]\)\)/);
|
|
147
|
+
});
|
|
148
|
+
});
|
|
149
|
+
});
|
|
150
|
+
|
|
151
|
+
//----------------------------------------------------------------------------------------------------------------------
|
|
@@ -5,6 +5,18 @@
|
|
|
5
5
|
* This swaps the primary/neutral colors from greyscale for a bolder look.
|
|
6
6
|
*/
|
|
7
7
|
|
|
8
|
+
@use 'shade-scale' as *;
|
|
9
|
+
|
|
10
|
+
$colorful-semantic-map: (
|
|
11
|
+
'neutral': 'blue',
|
|
12
|
+
'primary': 'orange',
|
|
13
|
+
'accent': 'blue',
|
|
14
|
+
'info': 'cyan',
|
|
15
|
+
'success': 'green',
|
|
16
|
+
'warning': 'yellow',
|
|
17
|
+
'danger': 'red',
|
|
18
|
+
);
|
|
19
|
+
|
|
8
20
|
[data-scheme="colorful"]
|
|
9
21
|
{
|
|
10
22
|
/* Neutral Kind */
|
|
@@ -55,4 +67,17 @@
|
|
|
55
67
|
--sk-info-active: color-mix(in oklch, var(--sk-info-base), var(--sk-color-gray-10) var(--sk-mix-amount-strong));
|
|
56
68
|
--sk-info-text: oklch(1 0 0);
|
|
57
69
|
--sk-info-text-contrast: var(--sk-color-gray-95);
|
|
70
|
+
|
|
71
|
+
/* Short aliases for the semantic kinds defined above. Must live inside the theme block so
|
|
72
|
+
* that `var(--sk-<kind>-base)` resolves on this element's cascade. */
|
|
73
|
+
--sk-neutral: var(--sk-neutral-base);
|
|
74
|
+
--sk-primary: var(--sk-primary-base);
|
|
75
|
+
--sk-accent: var(--sk-accent-base);
|
|
76
|
+
--sk-info: var(--sk-info-base);
|
|
77
|
+
--sk-success: var(--sk-success-base);
|
|
78
|
+
--sk-warning: var(--sk-warning-base);
|
|
79
|
+
--sk-danger: var(--sk-danger-base);
|
|
80
|
+
|
|
81
|
+
/* Tailwind-style shade scale (`--sk-primary-50`..`--sk-primary-950`, and so on). */
|
|
82
|
+
@include semantic-shades($colorful-semantic-map);
|
|
58
83
|
}
|
|
@@ -5,6 +5,18 @@
|
|
|
5
5
|
* This is the default, more subdued theme.
|
|
6
6
|
*/
|
|
7
7
|
|
|
8
|
+
@use 'shade-scale' as *;
|
|
9
|
+
|
|
10
|
+
$greyscale-semantic-map: (
|
|
11
|
+
'neutral': 'gray',
|
|
12
|
+
'primary': 'blue',
|
|
13
|
+
'accent': 'orange',
|
|
14
|
+
'info': 'cyan',
|
|
15
|
+
'success': 'green',
|
|
16
|
+
'warning': 'yellow',
|
|
17
|
+
'danger': 'red',
|
|
18
|
+
);
|
|
19
|
+
|
|
8
20
|
[data-scheme="greyscale"]
|
|
9
21
|
{
|
|
10
22
|
/* Neutral Kind */
|
|
@@ -55,4 +67,17 @@
|
|
|
55
67
|
--sk-info-active: color-mix(in oklch, var(--sk-info-base), var(--sk-color-gray-10) var(--sk-mix-amount-strong));
|
|
56
68
|
--sk-info-text: oklch(1 0 0);
|
|
57
69
|
--sk-info-text-contrast: var(--sk-color-gray-95);
|
|
70
|
+
|
|
71
|
+
/* Short aliases for the semantic kinds defined above. Must live inside the theme block so
|
|
72
|
+
* that `var(--sk-<kind>-base)` resolves on this element's cascade. */
|
|
73
|
+
--sk-neutral: var(--sk-neutral-base);
|
|
74
|
+
--sk-primary: var(--sk-primary-base);
|
|
75
|
+
--sk-accent: var(--sk-accent-base);
|
|
76
|
+
--sk-info: var(--sk-info-base);
|
|
77
|
+
--sk-success: var(--sk-success-base);
|
|
78
|
+
--sk-warning: var(--sk-warning-base);
|
|
79
|
+
--sk-danger: var(--sk-danger-base);
|
|
80
|
+
|
|
81
|
+
/* Tailwind-style shade scale (`--sk-primary-50`..`--sk-primary-950`, and so on). */
|
|
82
|
+
@include semantic-shades($greyscale-semantic-map);
|
|
58
83
|
}
|
|
@@ -0,0 +1,39 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* Theme shade-scale helper
|
|
3
|
+
*
|
|
4
|
+
* Shared map + mixin that each theme uses to emit Tailwind-style shade aliases
|
|
5
|
+
* (`--sk-primary-50`, `--sk-primary-200`, ..., `--sk-primary-950`) for the semantic kinds.
|
|
6
|
+
* The aliases point at foundation primitives (`--sk-color-<family>-05..95`) so they always
|
|
7
|
+
* follow the theme's chosen color family.
|
|
8
|
+
*/
|
|
9
|
+
|
|
10
|
+
@use 'sass:map';
|
|
11
|
+
|
|
12
|
+
// Tailwind-style shade names mapped to the SleekSpace primitive scale (05 / 10 / ... / 95).
|
|
13
|
+
$shade-map: (
|
|
14
|
+
50: '05',
|
|
15
|
+
100: '10',
|
|
16
|
+
200: '20',
|
|
17
|
+
300: '30',
|
|
18
|
+
400: '40',
|
|
19
|
+
500: '50',
|
|
20
|
+
600: '60',
|
|
21
|
+
700: '70',
|
|
22
|
+
800: '80',
|
|
23
|
+
900: '90',
|
|
24
|
+
950: '95',
|
|
25
|
+
);
|
|
26
|
+
|
|
27
|
+
/// Emit `--sk-<kind>-{50..950}` aliases for every (kind -> primitive-family) pair in $map.
|
|
28
|
+
/// Call from inside a theme's `[data-scheme="..."]` block so the aliases land on the same
|
|
29
|
+
/// element as the semantic `-base` tokens they pair with.
|
|
30
|
+
@mixin semantic-shades($map)
|
|
31
|
+
{
|
|
32
|
+
@each $kind, $primitive-family in $map
|
|
33
|
+
{
|
|
34
|
+
@each $shade, $primitive-step in $shade-map
|
|
35
|
+
{
|
|
36
|
+
--sk-#{ $kind }-#{ $shade }: var(--sk-color-#{ $primitive-family }-#{ $primitive-step });
|
|
37
|
+
}
|
|
38
|
+
}
|
|
39
|
+
}
|
|
@@ -8,6 +8,37 @@
|
|
|
8
8
|
* color kinds always reference the same foundation color.
|
|
9
9
|
*/
|
|
10
10
|
|
|
11
|
+
@use 'sass:map';
|
|
12
|
+
|
|
13
|
+
// Tailwind-style shade names mapped to the SleekSpace primitive scale (05 / 10 / ... / 95).
|
|
14
|
+
$sk-shade-map: (
|
|
15
|
+
50: '05',
|
|
16
|
+
100: '10',
|
|
17
|
+
200: '20',
|
|
18
|
+
300: '30',
|
|
19
|
+
400: '40',
|
|
20
|
+
500: '50',
|
|
21
|
+
600: '60',
|
|
22
|
+
700: '70',
|
|
23
|
+
800: '80',
|
|
24
|
+
900: '90',
|
|
25
|
+
950: '95',
|
|
26
|
+
);
|
|
27
|
+
|
|
28
|
+
// Each color kind's alias name paired with the foundation primitive family it draws from.
|
|
29
|
+
$sk-color-kinds: (
|
|
30
|
+
'boulder': 'gray',
|
|
31
|
+
'neon-blue': 'blue',
|
|
32
|
+
'light-blue': 'cyan',
|
|
33
|
+
'neon-orange': 'orange',
|
|
34
|
+
'neon-purple': 'purple',
|
|
35
|
+
'neon-green': 'green',
|
|
36
|
+
'neon-mint': 'mint',
|
|
37
|
+
'neon-pink': 'pink',
|
|
38
|
+
'yellow': 'yellow',
|
|
39
|
+
'red': 'red',
|
|
40
|
+
);
|
|
41
|
+
|
|
11
42
|
:root
|
|
12
43
|
{
|
|
13
44
|
/* ===================================================================
|
|
@@ -109,4 +140,39 @@
|
|
|
109
140
|
--sk-red-active: color-mix(in oklch, var(--sk-red-base), var(--sk-color-gray-10) var(--sk-mix-amount-strong));
|
|
110
141
|
--sk-red-text: oklch(1 0 0);
|
|
111
142
|
--sk-red-text-contrast: var(--sk-color-gray-95);
|
|
143
|
+
|
|
144
|
+
/* ===================================================================
|
|
145
|
+
* Short Aliases
|
|
146
|
+
*
|
|
147
|
+
* Shorthand names so consumers can write `var(--sk-neon-pink)` directly
|
|
148
|
+
* instead of `var(--sk-neon-pink-base)`. Semantic kinds (primary, accent,
|
|
149
|
+
* etc.) are aliased inside each theme block so `var(--sk-<kind>-base)`
|
|
150
|
+
* resolves against the theme's actual values.
|
|
151
|
+
* =================================================================== */
|
|
152
|
+
|
|
153
|
+
--sk-boulder: var(--sk-boulder-base);
|
|
154
|
+
--sk-neon-blue: var(--sk-neon-blue-base);
|
|
155
|
+
--sk-light-blue: var(--sk-light-blue-base);
|
|
156
|
+
--sk-neon-orange: var(--sk-neon-orange-base);
|
|
157
|
+
--sk-neon-purple: var(--sk-neon-purple-base);
|
|
158
|
+
--sk-neon-green: var(--sk-neon-green-base);
|
|
159
|
+
--sk-neon-mint: var(--sk-neon-mint-base);
|
|
160
|
+
--sk-neon-pink: var(--sk-neon-pink-base);
|
|
161
|
+
--sk-yellow: var(--sk-yellow-base);
|
|
162
|
+
--sk-red: var(--sk-red-base);
|
|
163
|
+
|
|
164
|
+
/* ===================================================================
|
|
165
|
+
* Tailwind-style shade scale for color kinds
|
|
166
|
+
*
|
|
167
|
+
* `--sk-neon-pink-500` = palette 50 (= base); `--sk-neon-pink-200` is two steps lighter,
|
|
168
|
+
* `--sk-neon-pink-800` is much darker, etc. Full scale: 50, 100..900, 950.
|
|
169
|
+
* =================================================================== */
|
|
170
|
+
|
|
171
|
+
@each $kind, $primitive-family in $sk-color-kinds
|
|
172
|
+
{
|
|
173
|
+
@each $shade, $primitive-step in $sk-shade-map
|
|
174
|
+
{
|
|
175
|
+
--sk-#{ $kind }-#{ $shade }: var(--sk-color-#{ $primitive-family }-#{ $primitive-step });
|
|
176
|
+
}
|
|
177
|
+
}
|
|
112
178
|
}
|
|
@@ -22,29 +22,37 @@ export type ComponentVariant = 'solid' | 'outline' | 'subtle' | 'ghost' | 'link'
|
|
|
22
22
|
|
|
23
23
|
/**
|
|
24
24
|
* Custom color props interface for components.
|
|
25
|
-
* Allows overriding component colors with any
|
|
25
|
+
* Allows overriding component colors with either a SleekSpace kind name or any CSS color value.
|
|
26
26
|
*/
|
|
27
27
|
export interface ComponentCustomColors
|
|
28
28
|
{
|
|
29
29
|
/**
|
|
30
|
-
* Base color for the component.
|
|
31
|
-
*
|
|
32
|
-
* -
|
|
33
|
-
* -
|
|
34
|
-
*
|
|
35
|
-
* - CSS
|
|
36
|
-
*
|
|
30
|
+
* Base color for the component. Accepts either:
|
|
31
|
+
* - A SleekSpace kind name: `"neutral"`, `"primary"`, `"accent"`, `"info"`, `"success"`,
|
|
32
|
+
* `"warning"`, `"danger"`, `"neon-blue"`, `"light-blue"`, `"neon-orange"`,
|
|
33
|
+
* `"neon-purple"`, `"neon-green"`, `"neon-mint"`, `"neon-pink"`, `"yellow"`, `"red"`,
|
|
34
|
+
* `"boulder"` — resolves to the matching `--sk-<kind>-base` token.
|
|
35
|
+
* - Any CSS color value: hex (`"#8B5CF6"`), oklch (`"oklch(0.7 0.25 300)"`),
|
|
36
|
+
* rgb/hsl (`"rgb(139, 92, 246)"`), a CSS variable (`"var(--my-color)"`), or a
|
|
37
|
+
* named color (`"rebeccapurple"`).
|
|
37
38
|
*
|
|
38
39
|
* When provided, this overrides the color from the `kind` prop.
|
|
39
40
|
*/
|
|
40
41
|
baseColor ?: string;
|
|
41
42
|
|
|
42
43
|
/**
|
|
43
|
-
* Text/foreground color for the component.
|
|
44
|
-
* If not provided,
|
|
45
|
-
*
|
|
44
|
+
* Text/foreground color for the component. Accepts the same kind names and CSS color values
|
|
45
|
+
* as `baseColor`. If not provided, falls back to the theme's neutral text color for legibility
|
|
46
|
+
* on arbitrary custom backgrounds.
|
|
46
47
|
*/
|
|
47
48
|
textColor ?: string;
|
|
49
|
+
|
|
50
|
+
/**
|
|
51
|
+
* Border color for the component. Accepts the same kind names and CSS color values as
|
|
52
|
+
* `baseColor`. Only honoured by components that render a visible border (panels, cards,
|
|
53
|
+
* inputs, etc.); ignored elsewhere.
|
|
54
|
+
*/
|
|
55
|
+
borderColor ?: string;
|
|
48
56
|
}
|
|
49
57
|
|
|
50
58
|
//----------------------------------------------------------------------------------------------------------------------
|
|
@@ -0,0 +1,75 @@
|
|
|
1
|
+
//----------------------------------------------------------------------------------------------------------------------
|
|
2
|
+
// Slot Utilities
|
|
3
|
+
//
|
|
4
|
+
// Helpers for inspecting Vue slot content. The common case: a component renders a wrapper div (or gates a
|
|
5
|
+
// fallback) based on whether a slot was passed. Checking `slots.foo` truthy only tells you a slot *function*
|
|
6
|
+
// exists; it doesn't tell you whether calling it produces anything. A slot whose content resolves to only
|
|
7
|
+
// comments, whitespace text, or a falsy `v-if` still evaluates truthy but renders nothing, which leaves
|
|
8
|
+
// behind empty wrappers that pick up gap/padding and distort layout.
|
|
9
|
+
//----------------------------------------------------------------------------------------------------------------------
|
|
10
|
+
|
|
11
|
+
import { Comment, Fragment, Text, type VNode } from 'vue';
|
|
12
|
+
|
|
13
|
+
//----------------------------------------------------------------------------------------------------------------------
|
|
14
|
+
|
|
15
|
+
// Accepts any slot-shaped callable. Covers both `Slot` (from useSlots) and the narrower
|
|
16
|
+
// `(props) => unknown` signatures that `defineSlots<...>()` produces for typed slots.
|
|
17
|
+
type SlotLike = (...args : any[]) => unknown;
|
|
18
|
+
|
|
19
|
+
//----------------------------------------------------------------------------------------------------------------------
|
|
20
|
+
|
|
21
|
+
export function hasRenderableContent(vnodes : VNode[]) : boolean
|
|
22
|
+
{
|
|
23
|
+
return vnodes.some((vnode) =>
|
|
24
|
+
{
|
|
25
|
+
if(vnode.type === Comment) { return false; }
|
|
26
|
+
|
|
27
|
+
if(vnode.type === Text)
|
|
28
|
+
{
|
|
29
|
+
return typeof vnode.children === 'string' && vnode.children.trim().length > 0;
|
|
30
|
+
}
|
|
31
|
+
|
|
32
|
+
if(vnode.type === Fragment && Array.isArray(vnode.children))
|
|
33
|
+
{
|
|
34
|
+
return hasRenderableContent(vnode.children as VNode[]);
|
|
35
|
+
}
|
|
36
|
+
|
|
37
|
+
return true;
|
|
38
|
+
});
|
|
39
|
+
}
|
|
40
|
+
|
|
41
|
+
//----------------------------------------------------------------------------------------------------------------------
|
|
42
|
+
|
|
43
|
+
export function hasSlotContent(slot : SlotLike | undefined, props ?: Record<string, unknown>) : boolean
|
|
44
|
+
{
|
|
45
|
+
if(!slot) { return false; }
|
|
46
|
+
return hasRenderableContent(slot(props) as VNode[]);
|
|
47
|
+
}
|
|
48
|
+
|
|
49
|
+
//----------------------------------------------------------------------------------------------------------------------
|
|
50
|
+
|
|
51
|
+
export function filterRenderableVNodes(vnodes : VNode[]) : VNode[]
|
|
52
|
+
{
|
|
53
|
+
return vnodes.flatMap((vnode) =>
|
|
54
|
+
{
|
|
55
|
+
if(vnode.type === Comment) { return []; }
|
|
56
|
+
|
|
57
|
+
if(vnode.type === Text)
|
|
58
|
+
{
|
|
59
|
+
if(typeof vnode.children === 'string' && vnode.children.trim().length > 0)
|
|
60
|
+
{
|
|
61
|
+
return [ vnode ];
|
|
62
|
+
}
|
|
63
|
+
return [];
|
|
64
|
+
}
|
|
65
|
+
|
|
66
|
+
if(vnode.type === Fragment && Array.isArray(vnode.children))
|
|
67
|
+
{
|
|
68
|
+
return filterRenderableVNodes(vnode.children as VNode[]);
|
|
69
|
+
}
|
|
70
|
+
|
|
71
|
+
return [ vnode ];
|
|
72
|
+
});
|
|
73
|
+
}
|
|
74
|
+
|
|
75
|
+
//----------------------------------------------------------------------------------------------------------------------
|