@skewedaspect/sleekspace-ui 0.4.0 → 0.5.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.
@@ -15256,7 +15256,7 @@ Defaulting to \`null\`.`);
15256
15256
  stroke: "currentColor",
15257
15257
  "stroke-width": "2"
15258
15258
  };
15259
- const _hoisted_6$3 = { class: "sk-alert-content" };
15259
+ const _hoisted_6$4 = { class: "sk-alert-content" };
15260
15260
  const _sfc_main$P = /* @__PURE__ */ vue.defineComponent({
15261
15261
  __name: "SkAlert",
15262
15262
  props: {
@@ -15354,7 +15354,7 @@ Defaulting to \`null\`.`);
15354
15354
  ])])) : vue.createCommentVNode("", true)
15355
15355
  ])
15356
15356
  ])) : vue.createCommentVNode("", true),
15357
- vue.createElementVNode("div", _hoisted_6$3, [
15357
+ vue.createElementVNode("div", _hoisted_6$4, [
15358
15358
  vue.renderSlot(_ctx.$slots, "default")
15359
15359
  ])
15360
15360
  ], 6);
@@ -17027,17 +17027,38 @@ Defaulting to \`null\`.`);
17027
17027
  }
17028
17028
  });
17029
17029
  const SkNumberInput = /* @__PURE__ */ _export_sfc(_sfc_main$s, [["__scopeId", "data-v-b589687f"]]);
17030
- const _hoisted_1$e = {
17030
+ const ThemeSymbol = Symbol("SkTheme");
17031
+ function provideTheme(initialTheme = "greyscale") {
17032
+ const currentTheme = vue.ref(initialTheme);
17033
+ const setTheme = (theme) => {
17034
+ currentTheme.value = theme;
17035
+ };
17036
+ const context2 = {
17037
+ currentTheme,
17038
+ setTheme
17039
+ };
17040
+ vue.provide(ThemeSymbol, context2);
17041
+ return context2;
17042
+ }
17043
+ function useTheme() {
17044
+ const context2 = vue.inject(ThemeSymbol);
17045
+ if (!context2) {
17046
+ throw new Error("useTheme must be called within an SkTheme component");
17047
+ }
17048
+ return context2;
17049
+ }
17050
+ const _hoisted_1$e = ["data-scheme"];
17051
+ const _hoisted_2$8 = {
17031
17052
  key: 0,
17032
17053
  class: "sk-page-header"
17033
17054
  };
17034
- const _hoisted_2$8 = { class: "sk-page-main" };
17035
- const _hoisted_3$6 = {
17055
+ const _hoisted_3$6 = { class: "sk-page-main" };
17056
+ const _hoisted_4$5 = {
17036
17057
  key: 0,
17037
17058
  class: "sk-page-sidebar"
17038
17059
  };
17039
- const _hoisted_4$5 = { class: "sk-page-content" };
17040
- const _hoisted_5$3 = {
17060
+ const _hoisted_5$3 = { class: "sk-page-content" };
17061
+ const _hoisted_6$3 = {
17041
17062
  key: 1,
17042
17063
  class: "sk-page-footer"
17043
17064
  };
@@ -17047,7 +17068,8 @@ Defaulting to \`null\`.`);
17047
17068
  sidebarPosition: { default: "left" },
17048
17069
  fixedHeader: { type: Boolean, default: false },
17049
17070
  fixedFooter: { type: Boolean, default: false },
17050
- sidebarWidth: { default: void 0 }
17071
+ sidebarWidth: { default: void 0 },
17072
+ theme: { default: void 0 }
17051
17073
  },
17052
17074
  setup(__props) {
17053
17075
  const props = __props;
@@ -17065,30 +17087,40 @@ Defaulting to \`null\`.`);
17065
17087
  "--sk-page-sidebar-width": props.sidebarWidth
17066
17088
  };
17067
17089
  });
17090
+ if (props.theme) {
17091
+ const { currentTheme, setTheme } = provideTheme(props.theme);
17092
+ vue.provide("sk-theme", currentTheme);
17093
+ vue.watch(() => props.theme, (newTheme) => {
17094
+ if (newTheme) {
17095
+ setTheme(newTheme);
17096
+ }
17097
+ });
17098
+ }
17068
17099
  return (_ctx, _cache) => {
17069
17100
  return vue.openBlock(), vue.createElementBlock("div", {
17070
17101
  class: vue.normalizeClass(classes.value),
17071
- style: vue.normalizeStyle(customStyles.value)
17102
+ style: vue.normalizeStyle(customStyles.value),
17103
+ "data-scheme": __props.theme
17072
17104
  }, [
17073
- _ctx.$slots.header ? (vue.openBlock(), vue.createElementBlock("header", _hoisted_1$e, [
17105
+ _ctx.$slots.header ? (vue.openBlock(), vue.createElementBlock("header", _hoisted_2$8, [
17074
17106
  vue.renderSlot(_ctx.$slots, "header", {}, void 0, true)
17075
17107
  ])) : vue.createCommentVNode("", true),
17076
- vue.createElementVNode("div", _hoisted_2$8, [
17077
- _ctx.$slots.sidebar ? (vue.openBlock(), vue.createElementBlock("aside", _hoisted_3$6, [
17108
+ vue.createElementVNode("div", _hoisted_3$6, [
17109
+ _ctx.$slots.sidebar ? (vue.openBlock(), vue.createElementBlock("aside", _hoisted_4$5, [
17078
17110
  vue.renderSlot(_ctx.$slots, "sidebar", {}, void 0, true)
17079
17111
  ])) : vue.createCommentVNode("", true),
17080
- vue.createElementVNode("main", _hoisted_4$5, [
17112
+ vue.createElementVNode("main", _hoisted_5$3, [
17081
17113
  vue.renderSlot(_ctx.$slots, "default", {}, void 0, true)
17082
17114
  ])
17083
17115
  ]),
17084
- _ctx.$slots.footer ? (vue.openBlock(), vue.createElementBlock("footer", _hoisted_5$3, [
17116
+ _ctx.$slots.footer ? (vue.openBlock(), vue.createElementBlock("footer", _hoisted_6$3, [
17085
17117
  vue.renderSlot(_ctx.$slots, "footer", {}, void 0, true)
17086
17118
  ])) : vue.createCommentVNode("", true)
17087
- ], 6);
17119
+ ], 14, _hoisted_1$e);
17088
17120
  };
17089
17121
  }
17090
17122
  });
17091
- const SkPage = /* @__PURE__ */ _export_sfc(_sfc_main$r, [["__scopeId", "data-v-0d313ffc"]]);
17123
+ const SkPage = /* @__PURE__ */ _export_sfc(_sfc_main$r, [["__scopeId", "data-v-ad672949"]]);
17092
17124
  const _hoisted_1$d = ["disabled", "aria-label", "aria-current"];
17093
17125
  const _hoisted_2$7 = { key: 0 };
17094
17126
  const _hoisted_3$5 = { key: 1 };
@@ -18896,26 +18928,6 @@ Defaulting to \`null\`.`);
18896
18928
  };
18897
18929
  }
18898
18930
  });
18899
- const ThemeSymbol = Symbol("SkTheme");
18900
- function provideTheme(initialTheme = "greyscale") {
18901
- const currentTheme = vue.ref(initialTheme);
18902
- const setTheme = (theme) => {
18903
- currentTheme.value = theme;
18904
- };
18905
- const context2 = {
18906
- currentTheme,
18907
- setTheme
18908
- };
18909
- vue.provide(ThemeSymbol, context2);
18910
- return context2;
18911
- }
18912
- function useTheme() {
18913
- const context2 = vue.inject(ThemeSymbol);
18914
- if (!context2) {
18915
- throw new Error("useTheme must be called within an SkTheme component");
18916
- }
18917
- return context2;
18918
- }
18919
18931
  const _hoisted_1 = ["data-scheme"];
18920
18932
  const _sfc_main = /* @__PURE__ */ vue.defineComponent({
18921
18933
  __name: "SkTheme",
package/dist/tokens.css CHANGED
@@ -158,6 +158,9 @@
158
158
  --sk-opacity-medium: 0.40;
159
159
  --sk-opacity-strong: 0.60;
160
160
  --sk-opacity-opaque: 1;
161
+ /* Semantic opacity aliases */
162
+ --sk-opacity-disabled: 0.5;
163
+ --sk-opacity-loading: 0.6;
161
164
  /* ===================================================================
162
165
  * Color Mixing Percentages
163
166
  * Tokenized mixing amounts for color-mix() function
@@ -351,6 +354,12 @@
351
354
  --sk-transition-easing-ease-in: ease-in;
352
355
  --sk-transition-easing-ease-out: ease-out;
353
356
  --sk-transition-easing-ease-in-out: ease-in-out;
357
+ /* ===================================================================
358
+ * Default Aliases
359
+ * Generic names that resolve to the most common values
360
+ * =================================================================== */
361
+ --sk-transition-duration-base: var(--sk-transition-duration-normal);
362
+ --sk-transition-easing: var(--sk-transition-easing-ease-out);
354
363
  /* ===================================================================
355
364
  * Common Transition Combinations
356
365
  * Convenience tokens for frequently used transitions
@@ -652,6 +661,10 @@
652
661
  *
653
662
  * Background and text colors for surfaces and general use.
654
663
  * These provide a consistent color system independent of component kinds.
664
+ *
665
+ * Defaults are defined on :root as fallbacks. Themes can override any of these
666
+ * via [data-scheme] selectors. The [data-scheme] rule also applies background
667
+ * and text color so that any themed element gets the correct surface treatment.
655
668
  */
656
669
  :root {
657
670
  /* ===================================================================
@@ -677,6 +690,16 @@
677
690
  --sk-border-subtle: var(--sk-color-gray-80); /* Subtle borders/dividers */
678
691
  }
679
692
 
693
+ /**
694
+ * Apply text color to any themed element so descendants inherit the correct
695
+ * color without needing to set it themselves. Background is intentionally NOT
696
+ * set here — page-level containers like SkPage handle their own background
697
+ * via the surface tokens.
698
+ */
699
+ [data-scheme] {
700
+ color: var(--sk-text-primary);
701
+ }
702
+
680
703
  /**
681
704
  * Semantic Tokens - Interactive
682
705
  *
@@ -31,7 +31,12 @@ Add new color primitives in `_foundation-colors.scss`:
31
31
  1. Create `src/styles/themes/_mytheme.scss`
32
32
  2. Define all 7 semantic kinds with the `[data-scheme="mytheme"]` selector
33
33
  3. Import in `themes/index.scss`: `@forward 'mytheme';`
34
- 4. Add to TypeScript types: `export type SkThemeName = 'greyscale' | 'colorful' | 'mytheme';`
34
+ 4. Register the TypeScript type via module augmentation:
35
+ ```ts
36
+ declare module '@skewedaspect/sleekspace-ui' {
37
+ interface SkThemeNameMap { mytheme : true; }
38
+ }
39
+ ```
35
40
  5. Use: `<SkTheme theme="mytheme">`
36
41
 
37
42
  ### Component Token Overrides
@@ -33,9 +33,22 @@ Beyond colors, foundation tokens cover spacing, borders, typography, transitions
33
33
  --sk-font-size-lg: 1.125rem
34
34
  --sk-font-size-xl: 1.25rem
35
35
 
36
- /* Transitions */
36
+ /* Transition Durations */
37
37
  --sk-transition-duration-instant: 0ms
38
38
  --sk-transition-duration-fast: 150ms
39
- --sk-transition-duration-normal: 200ms
40
- --sk-transition-duration-slow: 300ms
39
+ --sk-transition-duration-normal: 250ms
40
+ --sk-transition-duration-slow: 350ms
41
+ --sk-transition-duration-slower: 500ms
42
+
43
+ /* Transition Easing */
44
+ --sk-transition-easing-linear: linear
45
+ --sk-transition-easing-ease: ease
46
+ --sk-transition-easing-ease-in: ease-in
47
+ --sk-transition-easing-ease-out: ease-out
48
+ --sk-transition-easing-ease-in-out: ease-in-out
49
+
50
+ /* Common Transition Combinations */
51
+ --sk-transition-fast: all 150ms ease-out
52
+ --sk-transition-normal: all 250ms ease-out
53
+ --sk-transition-slow: all 350ms ease-out
41
54
  ```
@@ -24,19 +24,32 @@ Hover and active states are automatically calculated using CSS `color-mix()`:
24
24
 
25
25
  ### Surface & Text Semantics
26
26
 
27
- Background and text colors for layouts and content, separate from interactive component colors.
27
+ Background and text colors for layouts and content, separate from interactive component colors. Any element with a `data-scheme` attribute (set by `SkTheme` or `SkPage`'s `theme` prop) automatically inherits `color: var(--sk-text-primary)`. Page-level containers like `SkPage` set their own `background: var(--sk-surface-base)`.
28
28
 
29
29
  ```css
30
30
  /* Surface Colors */
31
- --sk-surface-base: var(--sk-color-gray-10)
32
- --sk-surface-raised: var(--sk-color-gray-05)
33
- --sk-surface-overlay: var(--sk-color-gray-20)
31
+ --sk-surface-base: var(--sk-color-gray-90) /* Main background */
32
+ --sk-surface-raised: var(--sk-color-gray-95) /* Elevated surfaces (cards, panels) */
33
+ --sk-surface-overlay: var(--sk-color-gray-80) /* Overlays (modals, dropdowns) */
34
34
 
35
35
  /* Text Colors */
36
- --sk-text-primary: var(--sk-color-gray-95)
37
- --sk-text-secondary: var(--sk-color-gray-70)
38
- --sk-text-tertiary: var(--sk-color-gray-50)
39
- --sk-text-disabled: var(--sk-color-gray-40)
36
+ --sk-text-primary: oklch(1 0 0) /* Primary body text (white) */
37
+ --sk-text-secondary: var(--sk-color-gray-30) /* Secondary/muted text */
38
+ --sk-text-tertiary: var(--sk-color-gray-50) /* Tertiary/placeholder text */
39
+ --sk-text-disabled: var(--sk-color-gray-60) /* Disabled text */
40
+
41
+ /* Border Colors */
42
+ --sk-border-normal: var(--sk-color-gray-70) /* Standard borders */
43
+ --sk-border-subtle: var(--sk-color-gray-80) /* Subtle borders/dividers */
44
+ ```
45
+
46
+ Custom themes can override any of these surface tokens to change the overall look:
47
+
48
+ ```css
49
+ [data-scheme='my-theme'] {
50
+ --sk-surface-base: var(--sk-color-purple-90);
51
+ --sk-text-primary: oklch(0.95 0.02 300);
52
+ }
40
53
  ```
41
54
 
42
55
  ### Interactive State Semantics
@@ -45,11 +58,13 @@ Unified focus and selection states across all interactive components.
45
58
 
46
59
  ```css
47
60
  /* Focus Ring */
48
- --sk-focus-ring-color: var(--sk-primary-base)
49
- --sk-focus-ring-width: var(--sk-border-width-normal)
61
+ --sk-focus-ring-color: var(--sk-primary-base)
62
+ --sk-focus-ring-width: var(--sk-border-width-normal)
50
63
  --sk-focus-ring-offset: 2px
64
+ --sk-focus-ring-style: var(--sk-border-style-solid)
65
+ --sk-focus-ring: var(--sk-focus-ring-width) var(--sk-focus-ring-style) var(--sk-focus-ring-color)
51
66
 
52
67
  /* Selection */
53
68
  --sk-selection-background: var(--sk-primary-base)
54
- --sk-selection-text: var(--sk-primary-text)
69
+ --sk-selection-text: var(--sk-primary-text)
55
70
  ```
@@ -4,7 +4,7 @@ section: themes
4
4
 
5
5
  ## Themes
6
6
 
7
- Themes map foundation colors to semantic kinds. Each theme is defined as a CSS attribute selector that overrides semantic tokens.
7
+ Themes map foundation colors to semantic kinds. Each theme is defined as a CSS attribute selector that overrides semantic tokens. `SkPage` automatically applies the theme's surface background; all themed elements inherit the correct text color.
8
8
 
9
9
  ### Available Themes
10
10
 
@@ -24,15 +24,26 @@ Themes are defined in `src/styles/themes/`. Each theme file exports a `[data-sch
24
24
  --sk-primary-base: var(--sk-color-mint-50);
25
25
  --sk-accent-base: var(--sk-color-orange-50);
26
26
  /* ... define all 7 semantic kinds */
27
+
28
+ /* Optional: override surface tokens */
29
+ --sk-surface-base: var(--sk-color-purple-90);
27
30
  }
28
31
  ```
29
32
 
30
33
  ### Using Themes
31
34
 
32
- Wrap your app in the `SkTheme` component:
35
+ Use `SkPage` with a `theme` prop (recommended) or wrap content in `SkTheme`:
33
36
 
34
37
  ```vue
38
+ <!-- Recommended: SkPage acts as theme provider -->
39
+ <SkPage theme="colorful">
40
+ <YourApp />
41
+ </SkPage>
42
+
43
+ <!-- Alternative: standalone theme wrapper -->
35
44
  <SkTheme theme="greyscale">
36
45
  <YourApp />
37
46
  </SkTheme>
38
47
  ```
48
+
49
+ See the [Theming Guide](/docs/guides/theming) for creating custom themes.
@@ -10,7 +10,7 @@ SleekSpace UI is a Vue 3 component library with a cyberpunk aesthetic. It provid
10
10
 
11
11
  ### Minimal Example
12
12
 
13
- The only requirement is wrapping your app in `SkTheme`. Here is the simplest setup:
13
+ The only requirement is establishing a theme context. The simplest way is with `SkTheme`:
14
14
 
15
15
  ```vue
16
16
  <template>
@@ -26,49 +26,50 @@ The only requirement is wrapping your app in `SkTheme`. Here is the simplest set
26
26
  </template>
27
27
  ```
28
28
 
29
- That's it. You can start using any SleekSpace component inside `SkTheme`.
29
+ That's it. You can start using any SleekSpace component inside the theme context. If you're using `SkPage`, you can skip `SkTheme` entirely — see the next section.
30
30
 
31
31
  ### Recommended Setup with SkPage
32
32
 
33
- For most applications, you will want a proper page layout with a header, sidebar, and content area. `SkPage` provides this structure:
33
+ For most applications, you will want a proper page layout with a header, sidebar, and content area. `SkPage` provides this structure and can act as a theme provider directly via its `theme` prop — no `SkTheme` wrapper needed:
34
34
 
35
35
  ```vue
36
36
  <template>
37
- <SkTheme theme="colorful">
38
- <SkPage fixed-header>
39
- <template #header>
40
- <SkNavBar kind="primary">
41
- <template #brand>My App</template>
42
- </SkNavBar>
43
- </template>
44
-
45
- <template #sidebar>
46
- <SkSidebar>
47
- <SkSidebarItem href="/">Home</SkSidebarItem>
48
- <SkSidebarItem href="/settings">Settings</SkSidebarItem>
49
- </SkSidebar>
50
- </template>
51
-
52
- <SkPanel kind="neutral">
53
- <h2>Welcome to SleekSpace UI</h2>
54
- <SkButton kind="accent" variant="solid">
55
- Get Started
56
- </SkButton>
57
- </SkPanel>
58
-
59
- <template #footer>
60
- <p>Footer content goes here</p>
61
- </template>
62
- </SkPage>
63
- </SkTheme>
37
+ <SkPage theme="colorful" fixed-header>
38
+ <template #header>
39
+ <SkNavBar kind="primary">
40
+ <template #brand>My App</template>
41
+ </SkNavBar>
42
+ </template>
43
+
44
+ <template #sidebar>
45
+ <SkSidebar>
46
+ <SkSidebarItem href="/">Home</SkSidebarItem>
47
+ <SkSidebarItem href="/settings">Settings</SkSidebarItem>
48
+ </SkSidebar>
49
+ </template>
50
+
51
+ <SkPanel kind="neutral">
52
+ <h2>Welcome to SleekSpace UI</h2>
53
+ <SkButton kind="accent" variant="solid">
54
+ Get Started
55
+ </SkButton>
56
+ </SkPanel>
57
+
58
+ <template #footer>
59
+ <p>Footer content goes here</p>
60
+ </template>
61
+ </SkPage>
64
62
  </template>
65
63
  ```
66
64
 
65
+ > **Note:** When `theme` is provided, `SkPage` sets `data-scheme` on its root element and provides theme context to all descendants — including portal components like dropdowns and modals. If you omit the `theme` prop, `SkPage` behaves as a pure layout component and you'll need an `SkTheme` wrapper instead.
66
+
67
67
  ### Why Use SkPage?
68
68
 
69
69
  `SkPage` is optional, but most applications will benefit from it:
70
70
 
71
71
  - **Full page layout structure** -- Provides header, sidebar, content, and footer regions in a single component.
72
+ - **Built-in theme provider** -- Pass a `theme` prop to eliminate the `SkTheme` wrapper entirely.
72
73
  - **Semantic HTML** -- Uses `<main>`, `<header>`, `<footer>`, and `<aside>` elements for better accessibility and SEO.
73
74
  - **Fixed headers and footers** -- Keep navigation visible while the content area scrolls independently.
74
75
  - **Flexible slots** -- All slots are optional. Use just a header, just a sidebar, or any combination. The layout adapts automatically.