Skip to content
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
Show all changes
34 commits
Select commit Hold shift + click to select a range
b168f05
wip
duncanmcclean Dec 17, 2025
10d63ff
wip
duncanmcclean Dec 17, 2025
7e4ef1c
wip
duncanmcclean Dec 17, 2025
d7d0d1f
wip
duncanmcclean Dec 17, 2025
3c8fbe9
wip
duncanmcclean Dec 17, 2025
054c493
wip
duncanmcclean Dec 17, 2025
d888ca2
wip
duncanmcclean Dec 17, 2025
2462c04
Merge branch 'master' into storybook-docs
duncanmcclean Dec 18, 2025
69256c7
wip
duncanmcclean Dec 18, 2025
29be200
wip
duncanmcclean Dec 18, 2025
6ebcedc
wip
duncanmcclean Dec 18, 2025
76bf241
wip
duncanmcclean Dec 18, 2025
24d1ef7
wip
duncanmcclean Dec 18, 2025
3a495e1
wip
duncanmcclean Dec 18, 2025
438be2e
wip
duncanmcclean Dec 18, 2025
91b3f60
wip
duncanmcclean Dec 18, 2025
2abd7ef
wip
duncanmcclean Dec 18, 2025
c2d94e4
wip
duncanmcclean Dec 18, 2025
ec516d8
wip
duncanmcclean Dec 18, 2025
3706329
wip
duncanmcclean Dec 18, 2025
215c552
wip
duncanmcclean Dec 18, 2025
978a3dc
wip
duncanmcclean Dec 18, 2025
38b0c0b
wip
duncanmcclean Dec 18, 2025
3df0f6e
no one wants to read my notes for claude
duncanmcclean Dec 18, 2025
cc37735
update assertion. we added a few missing exports
duncanmcclean Dec 18, 2025
05b26a6
knew i'd miss a spot or two
duncanmcclean Dec 18, 2025
1347128
fix icon in example
duncanmcclean Dec 19, 2025
8b431cc
wip
duncanmcclean Dec 19, 2025
42e6ce3
wip
duncanmcclean Dec 19, 2025
a9dd8d5
add jsdoc comments to combobox component
duncanmcclean Dec 19, 2025
2f8557c
Merge branch 'master' into storybook-docs
duncanmcclean Dec 19, 2025
0c1b4be
dont export or document data table just yet. its clearly quite broken…
jasonvarga Dec 19, 2025
c6610c9
comment out these quite broken ones
jasonvarga Dec 19, 2025
bcfc7b1
this too
jasonvarga Dec 19, 2025
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
5 changes: 5 additions & 0 deletions .storybook/manager-head.html
Original file line number Diff line number Diff line change
@@ -1,3 +1,8 @@
<link rel="icon" type="image/x-icon" href="favicon.ico">
<link rel="icon" type="image/png" sizes="16x16" href="favicon-16x16.png">
<link rel="icon" type="image/png" sizes="32x32" href="favicon-32x32.png">
<link rel="apple-touch-icon" sizes="180x180" href="apple-touch-icon.png">

<link rel="preconnect" href="https://fonts.googleapis.com">
<link rel="preconnect" href="https://fonts.gstatic.com" crossorigin>
<link href="https://fonts.googleapis.com/css2?family=Lexend:wght@400;500;600;700&family=Source+Code+Pro:wght@400;500&display=swap" rel="stylesheet">
5 changes: 5 additions & 0 deletions .storybook/preview-head.html
Original file line number Diff line number Diff line change
@@ -1,3 +1,8 @@
<link rel="icon" type="image/x-icon" href="favicon.ico">
<link rel="icon" type="image/png" sizes="16x16" href="favicon-16x16.png">
<link rel="icon" type="image/png" sizes="32x32" href="favicon-32x32.png">
<link rel="apple-touch-icon" sizes="180x180" href="apple-touch-icon.png">

<link rel="preconnect" href="https://use.typekit.net" crossorigin>
<link rel="preconnect" href="https://p.typekit.net" crossorigin>
<link rel="stylesheet" href="https://use.typekit.net/wyy0pka.css"/>
Expand Down
62 changes: 52 additions & 10 deletions .storybook/preview.ts
Original file line number Diff line number Diff line change
@@ -1,25 +1,67 @@
import type { Preview } from '@storybook/vue3-vite';
import { setup } from '@storybook/vue3';
import { create as createTheme } from 'storybook/theming';
import { router } from '@inertiajs/vue3';
import { action } from 'storybook/actions';
import type {Preview} from '@storybook/vue3-vite';
import {setup} from '@storybook/vue3';
import {create as createTheme} from 'storybook/theming';
import {router} from '@inertiajs/vue3';
import {action} from 'storybook/actions';
import './storybook.css';
import './theme.css';
import { translate } from '@/translations/translator';
import {translate} from '@/translations/translator';
import registerUiComponents from '@/bootstrap/ui';
import DateFormatter from '@/components/DateFormatter';
import cleanCodeSnippet from './clean-code-snippet';
import PortalVue from 'portal-vue';
import FullscreenHeader from '@/components/publish/FullscreenHeader.vue';
import Portal from '@/components/portals/Portal.vue';
import PortalTargets from '@/components/portals/PortalTargets.vue';

// Intercept Inertia navigation and log to Actions tab.
router.on('before', (event) => {
action('inertia navigate')(event.detail.visit.url);
return false;
});

// const portals = markRaw(new Portals());
// const stacks = new Stacks(portals);

setup(async (app) => {
window.__ = translate;

window.Statamic = {
$config: {
get(key) {
const config = {
linkToDocs: true,
paginationSize: 50,
paginationSizeOptions: [10, 25, 50, 100, 500],
};

return config[key] ?? null;
}
},
$commandPalette: {
add(command) {
//
}
},
$progress: {
loading(name, loading) {
//
}
}
};

app.config.globalProperties.__ = translate;
app.config.globalProperties.$date = new DateFormatter;
app.config.globalProperties.cp_url = (url) => url;
// app.config.globalProperties.$portals = portals;
// app.config.globalProperties.$stacks = stacks;

app.use(PortalVue, { portalName: 'v-portal' });

app.component('portal', Portal);
app.component('PortalTargets', PortalTargets);
app.component('publish-field-fullscreen-header', FullscreenHeader);

await registerUiComponents(app);
});

Expand Down Expand Up @@ -50,11 +92,11 @@ const preview: Preview = {
options: {
storySort: {
order: [
// 'Getting Started',
// 'Installation',
'*',
'Components'
'Overview',
'Components',
'*'
],
method: 'alphabetical',
},
},
},
Expand Down
Binary file added .storybook/public/apple-touch-icon.png
Loading
Sorry, something went wrong. Reload?
Sorry, we cannot display this file.
Sorry, this file is invalid so it cannot be displayed.
Binary file added .storybook/public/favicon-16x16.png
Loading
Sorry, something went wrong. Reload?
Sorry, we cannot display this file.
Sorry, this file is invalid so it cannot be displayed.
Binary file added .storybook/public/favicon-32x32.png
Loading
Sorry, something went wrong. Reload?
Sorry, we cannot display this file.
Sorry, this file is invalid so it cannot be displayed.
Binary file added .storybook/public/favicon.ico
Binary file not shown.
24 changes: 13 additions & 11 deletions .storybook/storybook.css
Original file line number Diff line number Diff line change
@@ -1,31 +1,33 @@
@import 'tailwindcss';
@import '../resources/css/ui.css';
@import '../resources/css/core/utilities.css';
@import '../resources/css/elements/tables.css';
@custom-variant dark (&:where(.dark, .dark *));

.sbdocs h1,
.sbdocs h2,
.sbdocs h3,
.sbdocs h4,
.sbdocs h5,
.sbdocs h6 {
.sbdocs h1:not(.sbdocs-preview *, .sbdocs-preview h1),
.sbdocs h2:not(.sbdocs-preview *, .sbdocs-preview h2),
.sbdocs h3:not(.sbdocs-preview *, .sbdocs-preview h3),
.sbdocs h4:not(.sbdocs-preview *, .sbdocs-preview h4),
.sbdocs h5:not(.sbdocs-preview *, .sbdocs-preview h5),
.sbdocs h6:not(.sbdocs-preview *, .sbdocs-preview h6) {
font-family: p22-mackinac-pro, serif;
}

.sbdocs h1 {
.sbdocs h1:not(.sbdocs-preview *, .sbdocs-preview h1) {
font-size: 2.5rem;
}

.sbdocs h2 {
.sbdocs h2:not(.sbdocs-preview *, .sbdocs-preview h2) {
font-size: 1.75rem;
font-weight: 600;
}

.sbdocs h3 {
.sbdocs h3:not(.sbdocs-preview *, .sbdocs-preview h3) {
font-size: 1.25rem;
}

.sbdocs p,
.sbdocs li {
.sbdocs p:not(.sbdocs-preview *, .sbdocs-preview p),
.sbdocs li:not(.sbdocs-preview *, .sbdocs-preview li) {
font-size: 1rem;
line-height: 1.6;
font-weight: 350;
Expand Down
1 change: 1 addition & 0 deletions .storybook/theme.css
Original file line number Diff line number Diff line change
Expand Up @@ -40,3 +40,4 @@ manually copy them here.
--theme-color-ui-accent-text: oklch(0.673 0.182 276.935);
}
}

1 change: 1 addition & 0 deletions packages/cms/src/ui.js
Original file line number Diff line number Diff line change
Expand Up @@ -17,6 +17,7 @@ export const {
CommandPaletteItem,
Context,
ContextFooter,
ContextHeader,
ContextItem,
ContextLabel,
ContextMenu,
Expand Down
1 change: 1 addition & 0 deletions resources/js/bootstrap/cms/ui.js
Original file line number Diff line number Diff line change
Expand Up @@ -17,6 +17,7 @@ export {
CommandPaletteItem,
Context,
ContextFooter,
ContextHeader,
ContextItem,
ContextLabel,
ContextMenu,
Expand Down
4 changes: 4 additions & 0 deletions resources/js/components/ui/Avatar.vue
Original file line number Diff line number Diff line change
Expand Up @@ -8,12 +8,16 @@ interface Asset {
}

interface User {
/** Custom initials to display */
initials?: string;
/** Avatar URL or Asset object */
avatar?: string | Asset;
/** User's name (used to generate initials if not provided) */
name?: string;
}

interface Props {
/** Object with optional properties: `name`, `initials`, `avatar` */
user: User;
}

Expand Down
11 changes: 11 additions & 0 deletions resources/js/components/ui/Badge.vue
Original file line number Diff line number Diff line change
Expand Up @@ -6,16 +6,27 @@ import Icon from './Icon/Icon.vue';
import { Link } from '@inertiajs/vue3';

const props = defineProps({
/** Appended text */
append: { type: [String, Number, Boolean, null], default: null },
/** The element or component this component should render as */
as: { type: String, default: 'div' },
/** Controls the color of the badge. <br><br> Options: `default`, `amber`, `black`, `blue`, `cyan`, `emerald`, `fuchsia`, `green`, `indigo`, `lime`, `orange`, `pink`, `purple`, `red`, `rose`, `sky`, `teal`, `violet`, `white`, `yellow` */
color: { type: String, default: 'default' },
/** The URL to link to */
href: { type: String, default: null },
/** When `href` is provided, this prop controls the link's `target` attribute */
target: { type: String, default: null },
/** Icon name. [Browse available icons](/?path=/story/components-icon--all-icons) */
icon: { type: String, default: null },
/** Icon name. Will display after the text. [Browse available icons](/?path=/story/components-icon--all-icons) */
iconAppend: { type: String, default: null },
/** When `true`, the badge will be displayed as a pill */
pill: { type: Boolean, default: false },
/** Prepended text */
prepend: { type: [String, Number, Boolean, null], default: null },
/** Controls the size of the badge. Options: `sm`, `default`, `lg` */
size: { type: String, default: 'default' },
/** Text to display in the badge */
text: { type: [String, Number, Boolean, null], default: null },
});

Expand Down
13 changes: 13 additions & 0 deletions resources/js/components/ui/Button/Button.vue
Original file line number Diff line number Diff line change
Expand Up @@ -6,18 +6,31 @@ import Icon from '../Icon/Icon.vue';
import { Link } from '@inertiajs/vue3';

const props = defineProps({
/** The element or component this component should render as */
as: { type: String, default: null },
/** The URL to link to */
href: { type: String, default: null },
/** When `href` is provided, this prop controls the link's `target` attribute */
target: { type: String, default: null },
/** Icon name. [Browse available icons](/?path=/story/components-icon--all-icons) */
icon: { type: String, default: null },
/** Icon name. Will display after the text. [Browse available icons](/?path=/story/components-icon--all-icons) */
iconAppend: { type: String, default: null },
/** When `true`, the button's padding will be adjusted to account for no text */
iconOnly: { type: Boolean, default: false },
/** When using `ghost` or `subtle` button variants, you can use the `inset` prop to remove any invisible padding for better alignment */
inset: { type: Boolean, default: false },
/** When `true`, the button shows an animated loading icon */
loading: { type: Boolean, default: false },
/** When `true`, the button will be rounded */
round: { type: Boolean, default: false },
/** Controls the size of the button. Options: `2xs`, `xs`, `sm`, `base`, `lg` */
size: { type: String, default: 'base' },
/** Text to display in the button */
text: { type: [String, Number, Boolean, null], default: null },
/** Unless `href` is provided, this component defaults to a `<button>`. This prop controls the button's `type` attribute */
type: { type: String, default: 'button' },
/** Controls the appearance of the button. Options: `default`, `primary`, `danger`, `filled`, `ghost`, `ghost-pressed`, `subtle`, `pressed` */
variant: { type: String, default: 'default' },
});

Expand Down
5 changes: 5 additions & 0 deletions resources/js/components/ui/Calendar/Calendar.vue
Original file line number Diff line number Diff line change
Expand Up @@ -20,10 +20,15 @@ import Icon from '../Icon/Icon.vue';
defineOptions({ name: 'Calendar' });

const props = defineProps({
/** The controlled value of the calendar. <br><br> Should be an ISO 8601 date and time string with a UTC offset (eg. `2021-11-07T07:45:00Z` or `2021-11-07T07:45:00-07:00`) */
modelValue: { type: [String, Object], default: null },
/** The earliest date that can be selected. Dates before this will be disabled. <br><br> Should be an ISO 8601 date and time string with a UTC offset (eg. `2021-11-07T07:45:00Z` or `2021-11-07T07:45:00-07:00`) */
min: { type: [String, Object], default: null },
/** The latest date that can be selected. Dates after this will be disabled. <br><br> Should be an ISO 8601 date and time string with a UTC offset (eg. `2021-11-07T07:45:00Z` or `2021-11-07T07:45:00-07:00`) */
max: { type: [String, Object], default: null },
/** If necessary, you can you swap out any of the internal Calendar components by passing an object to this prop. */
components: { type: Object, default: () => ({}) },
/** The number of months to display at once. */
numberOfMonths: { type: Number, default: 1 },
inline: { type: Boolean, default: false },
});
Expand Down
2 changes: 2 additions & 0 deletions resources/js/components/ui/Card/Card.vue
Original file line number Diff line number Diff line change
Expand Up @@ -2,7 +2,9 @@
import { cva } from 'cva';

const props = defineProps({
/** When `true`, the internal padding of the card is removed. */
inset: { type: Boolean, default: false },
/** Controls the appearance of the card. <br><br> Options: `default`, `flat` */
variant: { type: String, default: 'default' },
});

Expand Down
5 changes: 3 additions & 2 deletions resources/js/components/ui/CharacterCounter.vue
Original file line number Diff line number Diff line change
Expand Up @@ -2,11 +2,12 @@
import { computed, ref, watch } from 'vue';
import { cva } from 'cva';

const emit = defineEmits(['update:text']);

const props = defineProps({
/** The text to count characters from */
text: { type: String, default: '' },
/** The maximum number of characters allowed */
limit: { type: Number, default: null },
/** Number of characters remaining before showing the countdown number (default: 20) */
dangerZone: { type: Number, default: 20 },
});

Expand Down
3 changes: 3 additions & 0 deletions resources/js/components/ui/Checkbox/Group.vue
Original file line number Diff line number Diff line change
Expand Up @@ -3,8 +3,11 @@ import { useId } from 'vue';
import { CheckboxGroupRoot } from 'reka-ui';

defineProps({
/** When `true`, displays checkboxes horizontally */
inline: { type: Boolean, default: false },
/** The controlled value of the checkbox group */
modelValue: { type: Array, default: () => [] },
/** Name attribute for the checkbox group */
name: { type: String, default: () => useId() },
required: { type: Boolean, default: false },
});
Expand Down
10 changes: 10 additions & 0 deletions resources/js/components/ui/Checkbox/Item.vue
Original file line number Diff line number Diff line change
Expand Up @@ -4,16 +4,26 @@ import { computed } from 'vue';
import { cva } from 'cva';

const props = defineProps({
/** Controls the vertical alignment of the checkbox with its label. Options: `start`, `center` */
align: { type: String, default: 'start', validator: (value) => ['start', 'center'].includes(value) },
/** Description text to display below the label */
description: { type: String, default: null },
/** When `true`, disables the checkbox */
disabled: { type: Boolean, default: false },
/** Label text to display next to the checkbox */
label: { type: String, default: null },
/** The controlled value of the checkbox */
modelValue: { type: [Boolean, null], default: null },
/** Name attribute for the checkbox input */
name: { type: String, default: null },
readOnly: { type: Boolean, default: false },
/** Controls the size of the checkbox. Options: `sm`, `base` */
size: { type: String, default: 'base' },
/** When `true`, hides the label and description. Use this when the checkbox is used in a context where the label is provided elsewhere, like in a table cell */
solo: { type: Boolean, default: false },
/** Tab index for keyboard navigation */
tabindex: { type: Number, default: null },
/** Value of the checkbox when used in a group */
value: { type: [String, Number, Boolean] },
});

Expand Down
12 changes: 12 additions & 0 deletions resources/js/components/ui/CodeEditor.vue
Original file line number Diff line number Diff line change
Expand Up @@ -39,20 +39,32 @@ import 'codemirror/mode/yaml-frontmatter/yaml-frontmatter';
const emit = defineEmits(['update:mode', 'update:model-value', 'focus', 'blur']);

const props = defineProps({
/** When `true`, displays a mode selector dropdown */
allowModeSelection: { type: Boolean, default: true },
disabled: { type: Boolean, default: false },
fieldActions: { type: Array, default: () => [] },
/** Controls whether to indent with tabs or spaces. Options: `tabs`, `spaces` */
indentType: { type: String, default: 'tabs' },
/** Keyboard mapping for the editor. Options: `sublime`, `vim` */
keyMap: { type: String, default: 'sublime' },
/** When `true`, line numbers are displayed */
lineNumbers: { type: Boolean, default: true },
/** When `true`, long lines will wrap */
lineWrapping: { type: Boolean, default: true },
/** The syntax highlighting mode. Options: `clike`, `css`, `diff`, `go`, `haml`, `handlebars`, `htmlmixed`, `less`, `markdown`, `gfm`, `nginx`, `text/x-java`, `javascript`, `jsx`, `text/x-objectivec`, `php`, `python`, `ruby`, `scss`, `shell`, `sql`, `twig`, `vue`, `xml`, `yaml-frontmatter` */
mode: { type: String, default: 'javascript' },
/** The controlled value of the code editor */
modelValue: { type: String, default: '' },
readOnly: { type: Boolean, default: false },
/** Rulers configuration */
rulers: { type: Object, default: () => {} },
/** When `true`, displays the current mode label */
showModeLabel: { type: Boolean, default: true },
/** The width of a tab character */
tabSize: { type: Number, required: false },
/** Theme of the code editor. Options: `system`, `light`, `dark` */
colorMode: { type: String, default: 'system' },
/** Title displayed in fullscreen mode */
title: { type: String, default: () => __('Code Editor') },
});

Expand Down
Loading