picocrank 1.36.0 → 1.37.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.
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "picocrank",
3
- "version": "1.36.0",
3
+ "version": "1.37.0",
4
4
  "type": "module",
5
5
  "description": "A set of zero dependency Vue components built on the Femtocrank global CSS theme.",
6
6
  "main": "vite.config.js",
@@ -24,25 +24,25 @@
24
24
  "url": "https://github.com/jamesread/picocrank/issues"
25
25
  },
26
26
  "dependencies": {
27
- "@hugeicons/core-free-icons": "^4.3.0",
27
+ "@hugeicons/core-free-icons": "^4.3.5",
28
28
  "@hugeicons/vue": "^1.0.8",
29
- "@vitejs/plugin-vue": "^6.0.8",
30
- "femtocrank": "^2.7.1",
29
+ "@vitejs/plugin-vue": "^6.0.10",
30
+ "femtocrank": "^2.7.2",
31
31
  "unplugin-vue-components": "^32.1.0",
32
- "vite": "^8.2.2",
33
- "vue": "^3.5.42",
34
- "vue-router": "^5.3.1"
32
+ "vite": "^8.3.4",
33
+ "vue": "^3.5.43",
34
+ "vue-router": "^5.4.0"
35
35
  },
36
36
  "devDependencies": {
37
37
  "@eslint/js": "^10.0.1",
38
- "@vitest/coverage-v8": "^5.0.0",
39
- "@vue/test-utils": "^2.5.0",
40
- "eslint": "^10.10.0",
41
- "eslint-plugin-vue": "^10.11.0",
42
- "globals": "^17.12.0",
43
- "happy-dom": "^20.14.0",
38
+ "@vitest/coverage-v8": "^5.0.3",
39
+ "@vue/test-utils": "^2.5.1",
40
+ "eslint": "^10.12.0",
41
+ "eslint-plugin-vue": "^10.11.1",
42
+ "globals": "^17.13.0",
43
+ "happy-dom": "^20.14.6",
44
44
  "semantic-release": "^25.0.9",
45
- "vitest": "^5.0.0",
45
+ "vitest": "^5.0.3",
46
46
  "vue-eslint-parser": "^10.4.1"
47
47
  },
48
48
  "homepage": "https://github.com/jamesread/picocrank#readme"
package/router.js CHANGED
@@ -19,6 +19,7 @@ import { InformationCircleIcon } from '@hugeicons/core-free-icons';
19
19
  import { Loading03Icon } from '@hugeicons/core-free-icons';
20
20
  import { DragDropVerticalIcon } from '@hugeicons/core-free-icons';
21
21
  import { ArrowDown01Icon } from '@hugeicons/core-free-icons';
22
+ import { LayoutTopIcon } from '@hugeicons/core-free-icons';
22
23
 
23
24
  import {
24
25
  hubChildBreadcrumbs,
@@ -200,6 +201,16 @@ const routes = [
200
201
  breadcrumbs: hubChildBreadcrumbs('NavFeedbackStatusHub', 'DialogExample', 'Dialog'),
201
202
  }
202
203
  },
204
+ {
205
+ name: 'PageToolbarExample',
206
+ path: '/page-toolbar-example',
207
+ component: () => import('./vue/examples/PageToolbarExample.vue'),
208
+ meta: {
209
+ title: 'Page toolbar',
210
+ icon: LayoutTopIcon,
211
+ breadcrumbs: hubChildBreadcrumbs('NavLayoutsHub', 'PageToolbarExample', 'Page toolbar'),
212
+ }
213
+ },
203
214
  {
204
215
  name: 'LoadingAreaExample',
205
216
  path: '/loading-area-example',
@@ -0,0 +1,25 @@
1
+ import { describe, expect, it } from 'vitest'
2
+ import { mount } from '@vue/test-utils'
3
+ import PageToolbar from './PageToolbar.vue'
4
+
5
+ describe('PageToolbar', () => {
6
+ it('renders default-slot content in a toolbar', () => {
7
+ const wrapper = mount(PageToolbar, {
8
+ slots: {
9
+ default: '<button type="button">Refresh</button>',
10
+ },
11
+ })
12
+
13
+ expect(wrapper.attributes('role')).toBe('toolbar')
14
+ expect(wrapper.find('button').text()).toBe('Refresh')
15
+ expect(wrapper.attributes('aria-label')).toBeUndefined()
16
+ })
17
+
18
+ it('sets aria-label from the label prop', () => {
19
+ const wrapper = mount(PageToolbar, {
20
+ props: { label: 'Projects' },
21
+ })
22
+
23
+ expect(wrapper.attributes('aria-label')).toBe('Projects')
24
+ })
25
+ })
@@ -0,0 +1,54 @@
1
+ <template>
2
+ <div class="page-toolbar" role="toolbar" :aria-label="label || undefined">
3
+ <slot />
4
+ </div>
5
+ </template>
6
+
7
+ <script setup>
8
+ defineProps({
9
+ label: {
10
+ type: String,
11
+ default: '',
12
+ },
13
+ })
14
+ </script>
15
+
16
+ <style scoped>
17
+ /*
18
+ * Page-level toolbar that sticks under the fixed header and looks like a
19
+ * Femtocrank section joined to it (square top, rounded bottom).
20
+ * Override --page-toolbar-pull to match main's top padding (0 when main has none).
21
+ */
22
+ .page-toolbar {
23
+ --page-toolbar-pull: 1em;
24
+ position: sticky;
25
+ top: var(--picocrank-fixed-header-offset);
26
+ /* Below header.fixed (5) so its drop shadow draws over the toolbar. */
27
+ z-index: 4;
28
+ display: flex;
29
+ flex-wrap: wrap;
30
+ align-items: center;
31
+ justify-content: flex-end;
32
+ gap: 0.5rem;
33
+ margin-top: calc(-1 * var(--page-toolbar-pull));
34
+ margin-bottom: 1rem;
35
+ padding: calc(0.5rem + var(--page-toolbar-pull)) 1rem 0.5rem;
36
+ background-color: var(--section-bg-color);
37
+ border-radius: 0 0 .4em .4em;
38
+ box-shadow: 0 0 .5em var(--shadow-color);
39
+ }
40
+
41
+ .page-toolbar :slotted(button),
42
+ .page-toolbar :slotted(.button) {
43
+ padding: 0.4em 1em;
44
+ line-height: normal;
45
+ flex-shrink: 0;
46
+ }
47
+
48
+ /* Femtocrank drops main's padding on narrow screens. */
49
+ @media (max-width: 600px) {
50
+ .page-toolbar {
51
+ --page-toolbar-pull: 0px;
52
+ }
53
+ }
54
+ </style>
@@ -51,6 +51,11 @@ export const navSectionHubs = {
51
51
  title: 'Accordion',
52
52
  options: { description: 'Collapsible subsections' },
53
53
  },
54
+ {
55
+ name: 'PageToolbarExample',
56
+ title: 'Page toolbar',
57
+ options: { description: 'Sticky page-level actions joined to the header' },
58
+ },
54
59
  ],
55
60
  },
56
61
  NavDataDisplayHub: {
@@ -0,0 +1,31 @@
1
+ <template>
2
+ <PageToolbar label="Page actions">
3
+ <span class="subtle">{{ selected }} selected</span>
4
+ <button type="button" class="neutral" @click="selected++">Select another</button>
5
+ <button type="button" class="good">Save</button>
6
+ </PageToolbar>
7
+
8
+ <Section
9
+ title="Page toolbar"
10
+ :icon="Menu01Icon"
11
+ subtitle="Sticky page-level actions joined to the header"
12
+ >
13
+ <p>
14
+ Use <code>&lt;PageToolbar&gt;</code> when a page's actions apply to several
15
+ sibling sections, instead of wrapping them in one parent section (sections
16
+ cannot contain sections). It sticks under the fixed header while the page
17
+ scrolls. Scroll down to see it stay in place.
18
+ </p>
19
+ </Section>
20
+
21
+ <Section v-for="n in 6" :key="n" :title="`Group ${n}`">
22
+ <p v-for="line in 4" :key="line">Placeholder content line {{ line }} for group {{ n }}.</p>
23
+ </Section>
24
+ </template>
25
+
26
+ <script setup>
27
+ import { ref } from 'vue'
28
+ import { Menu01Icon } from '@hugeicons/core-free-icons'
29
+
30
+ const selected = ref(0)
31
+ </script>