@citizenplane/pimp 16.0.3 → 16.1.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/dist/pimp.es.js +313 -285
- package/dist/pimp.umd.js +21 -21
- package/dist/style.css +1 -1
- package/package.json +2 -1
- package/src/components/CpHeading.vue +4 -5
- package/src/components/CpText.vue +141 -0
- package/src/components/index.ts +2 -0
- package/src/stories/BaseInputLabel.stories.ts +36 -9
- package/src/stories/Colors.mdx +9 -0
- package/src/stories/Colors.stories.ts +177 -0
- package/src/stories/CpAccordion.stories.ts +187 -158
- package/src/stories/CpAccordionGroup.stories.ts +50 -94
- package/src/stories/CpAirlineLogo.stories.ts +49 -28
- package/src/stories/CpAlert.stories.ts +195 -158
- package/src/stories/CpBadge.stories.ts +259 -193
- package/src/stories/CpButton.stories.ts +257 -426
- package/src/stories/CpCheckbox.stories.ts +101 -29
- package/src/stories/CpContextualMenu.stories.ts +9 -8
- package/src/stories/CpDate.stories.ts +52 -25
- package/src/stories/CpDatepicker.stories.ts +57 -88
- package/src/stories/CpDialog.stories.ts +22 -1
- package/src/stories/CpHeading.stories.ts +59 -20
- package/src/stories/CpIcon.stories.ts +98 -31
- package/src/stories/CpInput.stories.ts +142 -67
- package/src/stories/CpItemActions.stories.ts +22 -27
- package/src/stories/CpLoader.stories.ts +54 -6
- package/src/stories/CpMenuItem.stories.ts +52 -26
- package/src/stories/CpMultiselect.stories.ts +52 -71
- package/src/stories/CpPartnerBadge.stories.ts +53 -74
- package/src/stories/CpRadio.stories.ts +44 -48
- package/src/stories/CpRadioGroup.stories.ts +46 -39
- package/src/stories/CpSelect.stories.ts +98 -39
- package/src/stories/CpSelectMenu.stories.ts +49 -57
- package/src/stories/CpSelectableButton.stories.ts +170 -81
- package/src/stories/CpSwitch.stories.ts +135 -133
- package/src/stories/CpTable.stories.ts +54 -1
- package/src/stories/CpTableEmptyState.stories.ts +11 -7
- package/src/stories/CpTabs.stories.ts +22 -4
- package/src/stories/CpTelInput.stories.ts +25 -23
- package/src/stories/CpText.stories.ts +131 -0
- package/src/stories/CpTextarea.stories.ts +59 -23
- package/src/stories/CpToast.stories.ts +53 -103
- package/src/stories/CpTooltip.stories.ts +82 -77
- package/src/stories/CpTransitionCounter.stories.ts +4 -0
- package/src/stories/CpTransitionExpand.stories.ts +11 -6
- package/src/stories/CpTransitionListItems.stories.ts +5 -0
- package/src/stories/CpTransitionSize.stories.ts +8 -0
- package/src/stories/CpTransitionSlide.stories.ts +4 -0
- package/src/stories/CpTransitionTabContent.stories.ts +4 -0
- package/src/stories/Dimensions.mdx +9 -0
- package/src/stories/Dimensions.stories.ts +119 -0
- package/src/stories/Easings.mdx +9 -0
- package/src/stories/Easings.stories.ts +101 -0
- package/src/stories/FocusRings.mdx +9 -0
- package/src/stories/FocusRings.stories.ts +74 -0
- package/src/stories/Shadows.mdx +9 -0
- package/src/stories/Shadows.stories.ts +100 -0
- package/src/stories/Typography.mdx +9 -0
- package/src/stories/Typography.stories.ts +181 -0
- package/src/stories/documentationStyles.ts +2 -10
- package/src/stories/tokenUtils.ts +259 -0
|
@@ -1,9 +1,12 @@
|
|
|
1
|
-
import type { Meta, StoryObj } from '@storybook/vue3'
|
|
1
|
+
import type { Args, Meta, StoryObj } from '@storybook/vue3'
|
|
2
2
|
|
|
3
3
|
import CpTooltip from '@/components/CpTooltip.vue'
|
|
4
4
|
|
|
5
|
+
const tooltipColors = ['accent', 'neutral'] as const
|
|
6
|
+
const tooltipPlacements = ['top', 'right', 'bottom', 'left'] as const
|
|
7
|
+
|
|
5
8
|
const meta = {
|
|
6
|
-
title: '
|
|
9
|
+
title: 'Atoms/CpTooltip',
|
|
7
10
|
component: CpTooltip,
|
|
8
11
|
argTypes: {
|
|
9
12
|
content: {
|
|
@@ -16,12 +19,12 @@ const meta = {
|
|
|
16
19
|
},
|
|
17
20
|
color: {
|
|
18
21
|
control: 'select',
|
|
19
|
-
options:
|
|
22
|
+
options: tooltipColors,
|
|
20
23
|
description: 'The color variant',
|
|
21
24
|
},
|
|
22
25
|
placement: {
|
|
23
26
|
control: 'select',
|
|
24
|
-
options:
|
|
27
|
+
options: tooltipPlacements,
|
|
25
28
|
description: 'The placement of the tooltip',
|
|
26
29
|
},
|
|
27
30
|
distance: {
|
|
@@ -34,53 +37,53 @@ const meta = {
|
|
|
34
37
|
export default meta
|
|
35
38
|
type Story = StoryObj<typeof meta>
|
|
36
39
|
|
|
40
|
+
const paddedRender = (args: Args) => ({
|
|
41
|
+
components: { CpTooltip },
|
|
42
|
+
setup() {
|
|
43
|
+
return { args }
|
|
44
|
+
},
|
|
45
|
+
template: `
|
|
46
|
+
<div style="padding: 100px; text-align: center;">
|
|
47
|
+
<CpTooltip v-bind="args">
|
|
48
|
+
<button>Hover me</button>
|
|
49
|
+
</CpTooltip>
|
|
50
|
+
</div>
|
|
51
|
+
`,
|
|
52
|
+
})
|
|
53
|
+
|
|
54
|
+
/**
|
|
55
|
+
* Default tooltip. Hover the trigger to reveal it. Use the controls to
|
|
56
|
+
* experiment with each prop in isolation.
|
|
57
|
+
*/
|
|
37
58
|
export const Default: Story = {
|
|
38
59
|
args: {
|
|
39
60
|
content: 'Tooltip content',
|
|
40
61
|
placement: 'top',
|
|
41
62
|
distance: 8,
|
|
42
63
|
},
|
|
43
|
-
render:
|
|
44
|
-
components: { CpTooltip },
|
|
45
|
-
setup() {
|
|
46
|
-
return { args }
|
|
47
|
-
},
|
|
48
|
-
template: `
|
|
49
|
-
<div style="padding: 100px; text-align: center;">
|
|
50
|
-
<CpTooltip v-bind="args">
|
|
51
|
-
<button>Hover me</button>
|
|
52
|
-
</CpTooltip>
|
|
53
|
-
</div>
|
|
54
|
-
`,
|
|
55
|
-
}),
|
|
64
|
+
render: paddedRender,
|
|
56
65
|
}
|
|
57
66
|
|
|
58
|
-
|
|
59
|
-
|
|
67
|
+
/* -------------------------------------------------------------------------- */
|
|
68
|
+
/* Placements */
|
|
69
|
+
/* -------------------------------------------------------------------------- */
|
|
70
|
+
|
|
71
|
+
/**
|
|
72
|
+
* All four placements rendered on one page. Tooltips flip automatically if
|
|
73
|
+
* they don't fit on the chosen side.
|
|
74
|
+
*/
|
|
75
|
+
export const Placements: Story = {
|
|
76
|
+
parameters: { controls: { disable: true } },
|
|
77
|
+
render: () => ({
|
|
60
78
|
components: { CpTooltip },
|
|
61
79
|
setup() {
|
|
62
|
-
return {
|
|
80
|
+
return { tooltipPlacements }
|
|
63
81
|
},
|
|
64
82
|
template: `
|
|
65
|
-
<div style="display: flex;
|
|
66
|
-
<div>
|
|
67
|
-
<CpTooltip content="
|
|
68
|
-
<button>
|
|
69
|
-
</CpTooltip>
|
|
70
|
-
</div>
|
|
71
|
-
<div>
|
|
72
|
-
<CpTooltip content="Right tooltip" placement="right">
|
|
73
|
-
<button>Right</button>
|
|
74
|
-
</CpTooltip>
|
|
75
|
-
</div>
|
|
76
|
-
<div>
|
|
77
|
-
<CpTooltip content="Bottom tooltip" placement="bottom">
|
|
78
|
-
<button>Bottom</button>
|
|
79
|
-
</CpTooltip>
|
|
80
|
-
</div>
|
|
81
|
-
<div>
|
|
82
|
-
<CpTooltip content="Left tooltip" placement="left">
|
|
83
|
-
<button>Left</button>
|
|
83
|
+
<div style="display: flex; gap: 32px; padding: 100px; justify-content: center; flex-wrap: wrap;">
|
|
84
|
+
<div v-for="placement in tooltipPlacements" :key="placement">
|
|
85
|
+
<CpTooltip :content="placement + ' tooltip'" :placement="placement">
|
|
86
|
+
<button>{{ placement }}</button>
|
|
84
87
|
</CpTooltip>
|
|
85
88
|
</div>
|
|
86
89
|
</div>
|
|
@@ -88,11 +91,17 @@ export const AllPlacements: Story = {
|
|
|
88
91
|
}),
|
|
89
92
|
}
|
|
90
93
|
|
|
94
|
+
/* -------------------------------------------------------------------------- */
|
|
95
|
+
/* Content */
|
|
96
|
+
/* -------------------------------------------------------------------------- */
|
|
97
|
+
|
|
98
|
+
/**
|
|
99
|
+
* Pass rich HTML content via the `#content` slot — perfect for links,
|
|
100
|
+
* formatting or small compositions.
|
|
101
|
+
*/
|
|
91
102
|
export const WithHTMLContent: Story = {
|
|
92
|
-
args: {
|
|
93
|
-
|
|
94
|
-
},
|
|
95
|
-
render: (args) => ({
|
|
103
|
+
args: { placement: 'top' },
|
|
104
|
+
render: (args: Args) => ({
|
|
96
105
|
components: { CpTooltip },
|
|
97
106
|
setup() {
|
|
98
107
|
return { args }
|
|
@@ -110,55 +119,51 @@ export const WithHTMLContent: Story = {
|
|
|
110
119
|
}),
|
|
111
120
|
}
|
|
112
121
|
|
|
113
|
-
|
|
114
|
-
|
|
115
|
-
|
|
116
|
-
|
|
117
|
-
|
|
118
|
-
render: (args) => ({
|
|
119
|
-
components: { CpTooltip },
|
|
120
|
-
setup() {
|
|
121
|
-
return { args }
|
|
122
|
-
},
|
|
123
|
-
template: `
|
|
124
|
-
<div style="padding: 100px; text-align: center;">
|
|
125
|
-
<CpTooltip v-bind="args">
|
|
126
|
-
<button type="button">Hover me</button>
|
|
127
|
-
<template #subcontent>
|
|
128
|
-
<p>Optional subcontent via slot, it can be a long text to see how it works and includes <b>HTML</b> <u>tags</u></p>
|
|
129
|
-
</template>
|
|
130
|
-
</CpTooltip>
|
|
131
|
-
</div>
|
|
132
|
-
`,
|
|
133
|
-
}),
|
|
134
|
-
}
|
|
135
|
-
|
|
136
|
-
export const WithSubcontentProp: Story = {
|
|
122
|
+
/**
|
|
123
|
+
* A secondary line of content displayed below the main content. Can be
|
|
124
|
+
* provided as a `subcontent` prop or through the `#subcontent` slot.
|
|
125
|
+
*/
|
|
126
|
+
export const WithSubcontent: Story = {
|
|
137
127
|
args: {
|
|
138
128
|
content: 'Main content',
|
|
139
129
|
subcontent: 'Optional subcontent via prop',
|
|
140
130
|
placement: 'top',
|
|
141
131
|
},
|
|
142
|
-
render: (args) => ({
|
|
132
|
+
render: (args: Args) => ({
|
|
143
133
|
components: { CpTooltip },
|
|
144
134
|
setup() {
|
|
145
135
|
return { args }
|
|
146
136
|
},
|
|
147
137
|
template: `
|
|
148
|
-
<div style="padding: 100px;
|
|
149
|
-
<
|
|
150
|
-
<
|
|
151
|
-
|
|
138
|
+
<div style="display: flex; gap: 48px; padding: 100px; justify-content: center; flex-wrap: wrap;">
|
|
139
|
+
<div>
|
|
140
|
+
<CpTooltip v-bind="args">
|
|
141
|
+
<button type="button">Subcontent via prop</button>
|
|
142
|
+
</CpTooltip>
|
|
143
|
+
</div>
|
|
144
|
+
<div>
|
|
145
|
+
<CpTooltip :content="args.content" :placement="args.placement">
|
|
146
|
+
<button type="button">Subcontent via slot</button>
|
|
147
|
+
<template #subcontent>
|
|
148
|
+
<p>Optional subcontent via slot, includes <b>HTML</b> <u>tags</u></p>
|
|
149
|
+
</template>
|
|
150
|
+
</CpTooltip>
|
|
151
|
+
</div>
|
|
152
152
|
</div>
|
|
153
153
|
`,
|
|
154
154
|
}),
|
|
155
155
|
}
|
|
156
156
|
|
|
157
|
+
/* -------------------------------------------------------------------------- */
|
|
158
|
+
/* States */
|
|
159
|
+
/* -------------------------------------------------------------------------- */
|
|
160
|
+
|
|
161
|
+
/**
|
|
162
|
+
* When `disabled` is `true` the tooltip never appears, even on hover.
|
|
163
|
+
*/
|
|
157
164
|
export const Disabled: Story = {
|
|
158
|
-
args: {
|
|
159
|
-
|
|
160
|
-
},
|
|
161
|
-
render: (args) => ({
|
|
165
|
+
args: { disabled: true },
|
|
166
|
+
render: (args: Args) => ({
|
|
162
167
|
components: { CpTooltip },
|
|
163
168
|
setup() {
|
|
164
169
|
return { args }
|
|
@@ -166,7 +171,7 @@ export const Disabled: Story = {
|
|
|
166
171
|
template: `
|
|
167
172
|
<div style="padding: 100px; text-align: center;">
|
|
168
173
|
<CpTooltip v-bind="args" content="You should not see me">
|
|
169
|
-
<div
|
|
174
|
+
<div>Disabled trigger</div>
|
|
170
175
|
</CpTooltip>
|
|
171
176
|
</div>
|
|
172
177
|
`,
|
|
@@ -24,6 +24,10 @@ const rowStyle = 'padding: 24px; display: inline-flex; align-items: center; just
|
|
|
24
24
|
|
|
25
25
|
const counterTextStyle = 'font-weight: bold; font-size: 4.5rem; line-height: 1; font-variant-numeric: tabular-nums;'
|
|
26
26
|
|
|
27
|
+
/**
|
|
28
|
+
* Counter transition that animates number changes. Use the +/- buttons
|
|
29
|
+
* (or the `duration` control) to see the slide-in / slide-out behaviour.
|
|
30
|
+
*/
|
|
27
31
|
export const Default: Story = {
|
|
28
32
|
args: {
|
|
29
33
|
duration: 150,
|
|
@@ -17,6 +17,10 @@ type Story = StoryObj<typeof meta>
|
|
|
17
17
|
|
|
18
18
|
const wrapperStyle = 'display: flex; flex-direction: column; align-items: center; gap: 12px;'
|
|
19
19
|
|
|
20
|
+
/**
|
|
21
|
+
* Animated height expansion. Wrap any element in `<CpTransitionExpand>`
|
|
22
|
+
* and toggle its rendering with `v-if` to smoothly expand/collapse.
|
|
23
|
+
*/
|
|
20
24
|
export const Default: Story = {
|
|
21
25
|
render: () => ({
|
|
22
26
|
components: { CpTransitionExpand },
|
|
@@ -35,14 +39,11 @@ export const Default: Story = {
|
|
|
35
39
|
</CpButton>
|
|
36
40
|
|
|
37
41
|
<CpTransitionExpand>
|
|
38
|
-
<div v-if="isExpanded" style="
|
|
39
|
-
background: #F3F4F6;
|
|
40
|
-
border-radius: 6px;
|
|
41
|
-
">
|
|
42
|
+
<div v-if="isExpanded" style="background: #F3F4F6; border-radius: 6px; padding: 16px;">
|
|
42
43
|
<h3 style="margin: 0 0 8px 0;">Expanded Content</h3>
|
|
43
44
|
<p style="margin: 0;">
|
|
44
|
-
This content
|
|
45
|
-
|
|
45
|
+
This content smoothly expands and collapses. The height transition is handled
|
|
46
|
+
automatically by the CpTransitionExpand component.
|
|
46
47
|
</p>
|
|
47
48
|
</div>
|
|
48
49
|
</CpTransitionExpand>
|
|
@@ -51,6 +52,10 @@ export const Default: Story = {
|
|
|
51
52
|
}),
|
|
52
53
|
}
|
|
53
54
|
|
|
55
|
+
/**
|
|
56
|
+
* The transition works with content of any height — no manual value
|
|
57
|
+
* needed.
|
|
58
|
+
*/
|
|
54
59
|
export const WithLongContent: Story = {
|
|
55
60
|
render: () => ({
|
|
56
61
|
components: { CpTransitionExpand },
|
|
@@ -51,6 +51,11 @@ const fabWrapperStyle = {
|
|
|
51
51
|
alignItems: 'flex-end',
|
|
52
52
|
}
|
|
53
53
|
|
|
54
|
+
/**
|
|
55
|
+
* Animate list insertions, removals and reorders with FLIP-based
|
|
56
|
+
* transitions. Use the + / shuffle buttons to see the enter, leave and
|
|
57
|
+
* move animations.
|
|
58
|
+
*/
|
|
54
59
|
export const Default: Story = {
|
|
55
60
|
args: {
|
|
56
61
|
disableOnLoad: false,
|
|
@@ -21,6 +21,10 @@ type Story = StoryObj<typeof meta>
|
|
|
21
21
|
|
|
22
22
|
const wrapperStyle = 'display: flex; flex-direction: column; align-items: center; gap: 12px;'
|
|
23
23
|
|
|
24
|
+
/**
|
|
25
|
+
* Animate a button's width when its inner label changes. Click the
|
|
26
|
+
* button to swap between a short and a longer label.
|
|
27
|
+
*/
|
|
24
28
|
export const Default: Story = {
|
|
25
29
|
args: {
|
|
26
30
|
type: 'width',
|
|
@@ -50,6 +54,10 @@ export const Default: Story = {
|
|
|
50
54
|
}),
|
|
51
55
|
}
|
|
52
56
|
|
|
57
|
+
/**
|
|
58
|
+
* Height mode — smoothly animates a dialog's body height as the step
|
|
59
|
+
* content (and therefore its size) changes.
|
|
60
|
+
*/
|
|
53
61
|
export const HeightTransition: Story = {
|
|
54
62
|
args: {
|
|
55
63
|
type: 'height',
|
|
@@ -28,6 +28,10 @@ const wrapperStyle = 'display: flex; flex-direction: column; align-items: center
|
|
|
28
28
|
const panelStyle =
|
|
29
29
|
'min-width: 260px; max-width: 320px; padding: 20px; border-radius: 12px; background: #f3f4f6; text-align: center;'
|
|
30
30
|
|
|
31
|
+
/**
|
|
32
|
+
* Slide between two panels. The `slideTo` prop controls direction
|
|
33
|
+
* (`top` or `left`) and `mode` follows Vue's `<Transition mode>` rules.
|
|
34
|
+
*/
|
|
31
35
|
export const Toggle: Story = {
|
|
32
36
|
name: 'Toggle',
|
|
33
37
|
args: {
|
|
@@ -36,6 +36,10 @@ const layoutStyle = 'display: flex; flex-direction: column; gap: 20px; min-width
|
|
|
36
36
|
const panelStyle =
|
|
37
37
|
'min-height: 120px; padding: 20px; border-radius: 12px; background: #f3f4f6; font-size: 15px; line-height: 1.5;'
|
|
38
38
|
|
|
39
|
+
/**
|
|
40
|
+
* Directional slide between tab panels. `direction` is driven by the
|
|
41
|
+
* current vs. previous tab index to slide forward or backward.
|
|
42
|
+
*/
|
|
39
43
|
export const Default: Story = {
|
|
40
44
|
args: {
|
|
41
45
|
duration: 300,
|
|
@@ -0,0 +1,119 @@
|
|
|
1
|
+
import type { Meta, StoryObj } from '@storybook/vue3'
|
|
2
|
+
|
|
3
|
+
import type { Token } from '@/stories/tokenUtils'
|
|
4
|
+
import {
|
|
5
|
+
copyableClass,
|
|
6
|
+
copyableCopiedClass,
|
|
7
|
+
readTokens,
|
|
8
|
+
sortTokensBySize,
|
|
9
|
+
splitRemPx,
|
|
10
|
+
tokenTableClass,
|
|
11
|
+
useCopier,
|
|
12
|
+
} from '@/stories/tokenUtils'
|
|
13
|
+
|
|
14
|
+
const meta: Meta = {
|
|
15
|
+
title: 'Foundations/Dimensions',
|
|
16
|
+
tags: ['!dev'],
|
|
17
|
+
parameters: {
|
|
18
|
+
layout: 'padded',
|
|
19
|
+
controls: { disable: true },
|
|
20
|
+
docs: { source: { code: null } },
|
|
21
|
+
},
|
|
22
|
+
}
|
|
23
|
+
|
|
24
|
+
export default meta
|
|
25
|
+
|
|
26
|
+
type Story = StoryObj
|
|
27
|
+
|
|
28
|
+
type DimensionKind = 'bar' | 'none' | 'radius' | 'square'
|
|
29
|
+
|
|
30
|
+
const previewStyle = (kind: DimensionKind, tokenName: string): string => {
|
|
31
|
+
const ref = `var(${tokenName})`
|
|
32
|
+
switch (kind) {
|
|
33
|
+
case 'bar':
|
|
34
|
+
return `height: 12px; width: ${ref}; max-width: 100%; background: var(--cp-background-accent-solid, #603dfd); border-radius: 4px;`
|
|
35
|
+
case 'radius':
|
|
36
|
+
return `width: 56px; height: 56px; background: var(--cp-background-accent-primary, #eaecff); border: 1px solid var(--cp-border-accent-primary, #ccd0ff); border-radius: ${ref};`
|
|
37
|
+
case 'square':
|
|
38
|
+
return `width: ${ref}; height: ${ref}; background: var(--cp-background-accent-solid, #603dfd); border-radius: 2px;`
|
|
39
|
+
case 'none':
|
|
40
|
+
return ''
|
|
41
|
+
}
|
|
42
|
+
}
|
|
43
|
+
|
|
44
|
+
type SectionArgs = { kind: DimensionKind; prefix: string }
|
|
45
|
+
|
|
46
|
+
const makeSectionStory = (section: SectionArgs): Story => ({
|
|
47
|
+
render: () => ({
|
|
48
|
+
setup() {
|
|
49
|
+
const tokens = sortTokensBySize(readTokens([section.prefix]))
|
|
50
|
+
const { copiedKey, copy } = useCopier()
|
|
51
|
+
return {
|
|
52
|
+
kind: section.kind,
|
|
53
|
+
tokens,
|
|
54
|
+
copiedKey,
|
|
55
|
+
copy,
|
|
56
|
+
tableClass: tokenTableClass,
|
|
57
|
+
copyClass: copyableClass,
|
|
58
|
+
copiedClass: copyableCopiedClass,
|
|
59
|
+
preview: (kind: DimensionKind, tokenName: string) => previewStyle(kind, tokenName),
|
|
60
|
+
split: (token: Token) => splitRemPx(token),
|
|
61
|
+
}
|
|
62
|
+
},
|
|
63
|
+
template: `
|
|
64
|
+
<table v-if="tokens.length > 0" :class="tableClass">
|
|
65
|
+
<thead>
|
|
66
|
+
<tr>
|
|
67
|
+
<th scope="col">Token</th>
|
|
68
|
+
<th scope="col">rem</th>
|
|
69
|
+
<th scope="col">px</th>
|
|
70
|
+
<th scope="col">Preview</th>
|
|
71
|
+
</tr>
|
|
72
|
+
</thead>
|
|
73
|
+
<tbody>
|
|
74
|
+
<tr v-for="token in tokens" :key="token.name">
|
|
75
|
+
<td>
|
|
76
|
+
<span
|
|
77
|
+
:class="[copyClass, copiedKey === token.name ? copiedClass : '']"
|
|
78
|
+
role="button"
|
|
79
|
+
tabindex="0"
|
|
80
|
+
:title="'Click to copy ' + token.name"
|
|
81
|
+
@click="copy(token.name)"
|
|
82
|
+
@keydown.enter.prevent="copy(token.name)"
|
|
83
|
+
@keydown.space.prevent="copy(token.name)"
|
|
84
|
+
>{{ copiedKey === token.name ? 'Copied!' : token.name }}</span>
|
|
85
|
+
</td>
|
|
86
|
+
<td>{{ split(token).rem }}</td>
|
|
87
|
+
<td>{{ split(token).px }}</td>
|
|
88
|
+
<td class="cp-token-table__preview">
|
|
89
|
+
<div :style="preview(kind, token.name)"></div>
|
|
90
|
+
</td>
|
|
91
|
+
</tr>
|
|
92
|
+
</tbody>
|
|
93
|
+
</table>
|
|
94
|
+
<div v-else style="padding: 12px 0; color: #9ca3af; font-size: 12px;">No tokens</div>
|
|
95
|
+
`,
|
|
96
|
+
}),
|
|
97
|
+
})
|
|
98
|
+
|
|
99
|
+
/**
|
|
100
|
+
* Responsive breakpoints. These values match the `min-width` media queries
|
|
101
|
+
* the design system uses to adapt layouts.
|
|
102
|
+
*/
|
|
103
|
+
export const Breakpoint: Story = makeSectionStory({ prefix: '--cp-breakpoint-', kind: 'none' })
|
|
104
|
+
|
|
105
|
+
/**
|
|
106
|
+
* Border radius scale, from sharp corners to fully rounded pill shapes.
|
|
107
|
+
*/
|
|
108
|
+
export const Radius: Story = makeSectionStory({ prefix: '--cp-radius-', kind: 'radius' })
|
|
109
|
+
|
|
110
|
+
/**
|
|
111
|
+
* Spacing scale used for padding, margin and gap. Rendered as horizontal
|
|
112
|
+
* bars to compare relative widths.
|
|
113
|
+
*/
|
|
114
|
+
export const Spacing: Story = makeSectionStory({ prefix: '--cp-spacing-', kind: 'bar' })
|
|
115
|
+
|
|
116
|
+
/**
|
|
117
|
+
* Width tokens used for icons, avatars and small fixed-size surfaces.
|
|
118
|
+
*/
|
|
119
|
+
export const Width: Story = makeSectionStory({ prefix: '--cp-width-', kind: 'square' })
|
|
@@ -0,0 +1,101 @@
|
|
|
1
|
+
import type { Meta, StoryObj } from '@storybook/vue3'
|
|
2
|
+
|
|
3
|
+
import { copyableClass, copyableCopiedClass, readTokens, tokenTableClass, useCopier } from '@/stories/tokenUtils'
|
|
4
|
+
|
|
5
|
+
const meta: Meta = {
|
|
6
|
+
title: 'Foundations/Easings',
|
|
7
|
+
tags: ['!dev'],
|
|
8
|
+
parameters: {
|
|
9
|
+
layout: 'padded',
|
|
10
|
+
controls: { disable: true },
|
|
11
|
+
docs: { source: { code: null } },
|
|
12
|
+
},
|
|
13
|
+
}
|
|
14
|
+
|
|
15
|
+
export default meta
|
|
16
|
+
|
|
17
|
+
type Story = StoryObj
|
|
18
|
+
|
|
19
|
+
/**
|
|
20
|
+
* Cubic-bezier curves used for the design-system transitions. Hover (or
|
|
21
|
+
* focus) any track to play the animation and compare curves side by side.
|
|
22
|
+
*/
|
|
23
|
+
export const Curves: Story = {
|
|
24
|
+
render: () => ({
|
|
25
|
+
setup() {
|
|
26
|
+
const easings = readTokens(['--cp-easing-'])
|
|
27
|
+
const { copiedKey, copy } = useCopier()
|
|
28
|
+
return {
|
|
29
|
+
easings,
|
|
30
|
+
copiedKey,
|
|
31
|
+
copy,
|
|
32
|
+
tableClass: tokenTableClass,
|
|
33
|
+
copyClass: copyableClass,
|
|
34
|
+
copiedClass: copyableCopiedClass,
|
|
35
|
+
ballStyle: (tokenName: string) => `transition-timing-function: var(${tokenName});`,
|
|
36
|
+
}
|
|
37
|
+
},
|
|
38
|
+
template: `
|
|
39
|
+
<div>
|
|
40
|
+
<style>
|
|
41
|
+
.cp-easing-track {
|
|
42
|
+
position: relative;
|
|
43
|
+
width: 220px;
|
|
44
|
+
height: 36px;
|
|
45
|
+
background: #f3f4f6;
|
|
46
|
+
border-radius: 18px;
|
|
47
|
+
overflow: hidden;
|
|
48
|
+
}
|
|
49
|
+
.cp-easing-ball {
|
|
50
|
+
position: absolute;
|
|
51
|
+
top: 4px;
|
|
52
|
+
left: 4px;
|
|
53
|
+
width: 28px;
|
|
54
|
+
height: 28px;
|
|
55
|
+
border-radius: 50%;
|
|
56
|
+
background: var(--cp-background-accent-solid, #603dfd);
|
|
57
|
+
transition-property: transform;
|
|
58
|
+
transition-duration: 900ms;
|
|
59
|
+
transform: translateX(0);
|
|
60
|
+
}
|
|
61
|
+
.cp-easing-track:hover .cp-easing-ball,
|
|
62
|
+
.cp-easing-track:focus-within .cp-easing-ball {
|
|
63
|
+
transform: translateX(184px);
|
|
64
|
+
}
|
|
65
|
+
</style>
|
|
66
|
+
<p style="margin: 0 0 12px 0; color: #6b7280; font-size: 12px;">Hover a track to play the transition.</p>
|
|
67
|
+
<table v-if="easings.length > 0" :class="tableClass">
|
|
68
|
+
<thead>
|
|
69
|
+
<tr>
|
|
70
|
+
<th scope="col">Token</th>
|
|
71
|
+
<th scope="col">Value</th>
|
|
72
|
+
<th scope="col">Preview</th>
|
|
73
|
+
</tr>
|
|
74
|
+
</thead>
|
|
75
|
+
<tbody>
|
|
76
|
+
<tr v-for="token in easings" :key="token.name">
|
|
77
|
+
<td>
|
|
78
|
+
<span
|
|
79
|
+
:class="[copyClass, copiedKey === token.name ? copiedClass : '']"
|
|
80
|
+
role="button"
|
|
81
|
+
tabindex="0"
|
|
82
|
+
:title="'Click to copy ' + token.name"
|
|
83
|
+
@click="copy(token.name)"
|
|
84
|
+
@keydown.enter.prevent="copy(token.name)"
|
|
85
|
+
@keydown.space.prevent="copy(token.name)"
|
|
86
|
+
>{{ copiedKey === token.name ? 'Copied!' : token.name }}</span>
|
|
87
|
+
</td>
|
|
88
|
+
<td>{{ token.value }}</td>
|
|
89
|
+
<td class="cp-token-table__preview">
|
|
90
|
+
<div class="cp-easing-track" tabindex="0">
|
|
91
|
+
<div class="cp-easing-ball" :style="ballStyle(token.name)"></div>
|
|
92
|
+
</div>
|
|
93
|
+
</td>
|
|
94
|
+
</tr>
|
|
95
|
+
</tbody>
|
|
96
|
+
</table>
|
|
97
|
+
<div v-else style="padding: 12px 0; color: #9ca3af; font-size: 12px;">No tokens</div>
|
|
98
|
+
</div>
|
|
99
|
+
`,
|
|
100
|
+
}),
|
|
101
|
+
}
|
|
@@ -0,0 +1,74 @@
|
|
|
1
|
+
import type { Meta, StoryObj } from '@storybook/vue3'
|
|
2
|
+
|
|
3
|
+
import { copyableClass, copyableCopiedClass, readTokens, tokenTableClass, useCopier } from '@/stories/tokenUtils'
|
|
4
|
+
|
|
5
|
+
const meta: Meta = {
|
|
6
|
+
title: 'Foundations/Focus Rings',
|
|
7
|
+
tags: ['!dev'],
|
|
8
|
+
parameters: {
|
|
9
|
+
layout: 'padded',
|
|
10
|
+
controls: { disable: true },
|
|
11
|
+
docs: { source: { code: null } },
|
|
12
|
+
},
|
|
13
|
+
}
|
|
14
|
+
|
|
15
|
+
export default meta
|
|
16
|
+
|
|
17
|
+
type Story = StoryObj
|
|
18
|
+
|
|
19
|
+
const previewStyle = (tokenName: string): string =>
|
|
20
|
+
`display: inline-flex; align-items: center; justify-content: center; height: 40px; padding: 0 18px; border-radius: 8px; background: #ffffff; border: 1px solid #e9eaf6; color: #36384d; font-size: 14px; box-shadow: var(${tokenName});`
|
|
21
|
+
|
|
22
|
+
/**
|
|
23
|
+
* Composite focus-ring tokens (one token per color role). Each token is a
|
|
24
|
+
* multi-layered `box-shadow` that produces a consistent, accessible focus
|
|
25
|
+
* outline when applied to an element.
|
|
26
|
+
*/
|
|
27
|
+
export const Composite: Story = {
|
|
28
|
+
render: () => ({
|
|
29
|
+
setup() {
|
|
30
|
+
const composites = readTokens([/^--cp-shadow-focus-ring-[^-]+$/])
|
|
31
|
+
const { copiedKey, copy } = useCopier()
|
|
32
|
+
return {
|
|
33
|
+
composites,
|
|
34
|
+
copiedKey,
|
|
35
|
+
copy,
|
|
36
|
+
tableClass: tokenTableClass,
|
|
37
|
+
copyClass: copyableClass,
|
|
38
|
+
copiedClass: copyableCopiedClass,
|
|
39
|
+
preview: (tokenName: string) => previewStyle(tokenName),
|
|
40
|
+
}
|
|
41
|
+
},
|
|
42
|
+
template: `
|
|
43
|
+
<table v-if="composites.length > 0" :class="tableClass">
|
|
44
|
+
<thead>
|
|
45
|
+
<tr>
|
|
46
|
+
<th scope="col">Token</th>
|
|
47
|
+
<th scope="col">Value</th>
|
|
48
|
+
<th scope="col">Preview</th>
|
|
49
|
+
</tr>
|
|
50
|
+
</thead>
|
|
51
|
+
<tbody>
|
|
52
|
+
<tr v-for="token in composites" :key="token.name">
|
|
53
|
+
<td>
|
|
54
|
+
<span
|
|
55
|
+
:class="[copyClass, copiedKey === token.name ? copiedClass : '']"
|
|
56
|
+
role="button"
|
|
57
|
+
tabindex="0"
|
|
58
|
+
:title="'Click to copy ' + token.name"
|
|
59
|
+
@click="copy(token.name)"
|
|
60
|
+
@keydown.enter.prevent="copy(token.name)"
|
|
61
|
+
@keydown.space.prevent="copy(token.name)"
|
|
62
|
+
>{{ copiedKey === token.name ? 'Copied!' : token.name }}</span>
|
|
63
|
+
</td>
|
|
64
|
+
<td>{{ token.value }}</td>
|
|
65
|
+
<td class="cp-token-table__preview">
|
|
66
|
+
<span :style="preview(token.name)">Focused</span>
|
|
67
|
+
</td>
|
|
68
|
+
</tr>
|
|
69
|
+
</tbody>
|
|
70
|
+
</table>
|
|
71
|
+
<div v-else style="padding: 12px 0; color: #9ca3af; font-size: 12px;">No tokens</div>
|
|
72
|
+
`,
|
|
73
|
+
}),
|
|
74
|
+
}
|