Skip to content
Open
Show file tree
Hide file tree
Changes from all commits
Commits
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
20 changes: 20 additions & 0 deletions index.html
Original file line number Diff line number Diff line change
@@ -0,0 +1,20 @@
<!DOCTYPE html>
<html>

<head>
<meta charset="utf-8">
<title>Decap CMS Playground</title>
<meta name="viewport" content="width=device-width, initial-scale=1">
</head>

<body>
<div id="root"></div>
<script>
window.CMS_MANUAL_INIT = true;
</script>
<script src="https://unpkg.com/decap-cms@^3.0.0/dist/decap-cms.js"></script>
<script type="module" src="./src/main.js"></script>

</body>

</html>
3,131 changes: 996 additions & 2,135 deletions package-lock.json

Large diffs are not rendered by default.

38 changes: 21 additions & 17 deletions package.json
Original file line number Diff line number Diff line change
@@ -1,7 +1,7 @@
{
"name": "decap-cms-widget-id",
"version": "2.0.0",
"description": "Id widget for Netlify CMS",
"description": "ID widget for DecapCMS",
"main": "./dist/index.js",
"files": [
"dist",
Expand All @@ -11,25 +11,29 @@
"author": "Wojciech Kaluzny <[email protected]>",
"license": "MIT",
"repository": "https://github.com/clean-commit/decap-cms-widget-id",
"peerDependencies": {
"react": "^18.3.1",
"react-dom": "^18.3.1"
"devDependencies": {
"@rollup/plugin-replace": "^5.0.2",
"@vitejs/plugin-react": "^4.0.4",
"react": "^19.1.0",
"react-dom": "^19.1.0",
"vite": "^4.4.9",
"vite-plugin-css-injected-by-js": "^3.3.0"
},
"dependencies": {
"@babel/polyfill": "^7.12.1",
"shortid": "^2.2.16"
"prop-types": "^15.8.1",
"rollup-plugin-copy": "^3.4.0",
"shortid": "^2.2.17"
},
"scripts": {
"build": "rm -rf dist && NODE_ENV=production babel src --out-dir dist --copy-files"
"peerDependencies": {
"react": "^19.1.0",
"react-dom": "^19.1.0"
},
"publishConfig": {
"access": "public"
"engines": {
"node": ">=18"
},
"devDependencies": {
"@babel/cli": "^7.17.10",
"@babel/core": "^7.18.2",
"@babel/preset-env": "^7.18.2",
"@babel/preset-react": "^7.17.12",
"@types/react": "^16.8.23"
"scripts": {
"dev": "vite",
"build": "NODE_ENV=production vite build",
"preview": "vite preview"
}
}
}
20 changes: 20 additions & 0 deletions public/config.yml
Original file line number Diff line number Diff line change
@@ -0,0 +1,20 @@
backend:
name: test-repo
login: false
media_folder: assets
collections:
- label: Test
name: test
files:
- file: test.yml
name: test
label: Test
fields:
- name: test_widget
label: Test Widget
widget: id
regenerate: false
prefix: pre
- name: string_for_testing
label: String Widget
widget: string
124 changes: 124 additions & 0 deletions src/Control.jsx
Original file line number Diff line number Diff line change
@@ -0,0 +1,124 @@
import React, { useEffect, useState } from 'react';
import shortid from 'shortid';
import PropTypes from 'prop-types';

const wrapper = {
display: 'flex',
justifyContent: 'space-between',
width: '100%',
padding: '16px 20px',
margin: '0px',
border: '2px solid rgb(223, 223, 227)',
borderRadius: '0px 5px 5px',
outline: '0px',
boxShadow: 'none',
backgroundColor: 'rgb(255, 255, 255)',
color: 'rgb(205, 205, 205)',
transition: 'border-color 0.2s ease 0s',
position: 'relative',
fontSize: '15px',
};

const button = {
marginLeft: '1em',
display: 'block',
border: '0px',
cursor: 'pointer',
height: '27px',
lineHeight: '27px',
fontSize: '12px',
fontWeight: 600,
borderRadius: '3px',
padding: '0px 14px',
backgroundColor: 'rgb(121, 130, 145)',
color: 'rgb(255, 255, 255)',
marginRight: '8px',
};

export default class Control extends React.Component {
static propTypes = {
field: PropTypes.any,
onChange: PropTypes.func.isRequired,
forID: PropTypes.string,
value: PropTypes.node,
classNameWrapper: PropTypes.string.isRequired,
setActiveStyle: PropTypes.func.isRequired,
setInactiveStyle: PropTypes.func.isRequired,
};

static defaultProps = {
value: ''
};

// The selection to maintain for the input element
_sel = 0;

// The input element ref
_el = null;

componentDidMount() {
// Manually validate PropTypes - React 19 breaking change
PropTypes.checkPropTypes(Control.propTypes, this.props, 'prop', 'Control');
// Set a default if there is not one already:
if ( !this.props.value ) {
this.props.onChange( this.generateId() );
}
}

// NOTE: This prevents the cursor from jumping to the end of the text for
// nested inputs. In other words, this is not an issue on top-level text
// fields such as the `title` of a collection post. However, it becomes an
// issue on fields nested within other components, namely widgets nested
// within a `markdown` widget. For example, the alt text on a block image
// within markdown.
// SEE: https://github.com/decaporg/decap-cms/issues/4539
// SEE: https://github.com/decaporg/decap-cms/issues/3578
componentDidUpdate() {
if (this._el && this._el.selectionStart !== this._sel) {
this._el.setSelectionRange(this._sel, this._sel);
}
}

handleChange = e => {
this._sel = e.target.selectionStart;
this.props.onChange(e.target.value);
};

generateId = () => {
const usePrefix = this.props.field.get('prefix');
const prefix = usePrefix ? usePrefix + '-' : '';
return prefix + shortid();
};


render() {
const { field, onChange, forID, value, classNameWrapper, setActiveStyle, setInactiveStyle } = this.props;

return (
<div style={wrapper}>
<input
type='hidden'
id={forID}
value={value}
onChange={(e) => onChange(e.target.value.trim())}
/>
<span
style={{
lineHeight: '1.6em',
}}>
{value || this.generateId()}
</span>
{ field.get('regenerate', false ) ? (
<button
onClick={() => {
onChange(this.generateId());
}}
style={button}>
Regenerate ID
</button>
) : '' }
</div>
);
}
}

4 changes: 4 additions & 0 deletions src/dev.js
Original file line number Diff line number Diff line change
@@ -0,0 +1,4 @@
CMS.registerWidget('id', window.IdControl)//, window.IdPreview);
// Relies on the admin HTML file using `window.CMS_MANUAL_INIT = true;`
// This ensures the init always happens after the widget is registered.
CMS.init();
91 changes: 0 additions & 91 deletions src/index.js

This file was deleted.

14 changes: 14 additions & 0 deletions src/main.js
Original file line number Diff line number Diff line change
@@ -0,0 +1,14 @@
import Control from './Control.jsx'
//import Preview from './Preview.jsx'

if (typeof window !== 'undefined') {
window.IdControl = Control
//window.IdPreview = Preview
}

export { Control as IdControl} //, Preview as IdPreview }

if (!import.meta.env.PROD) {
console.log('[decap-cms-widget-starter] Running in development mode...')
import("./dev.js")
}
52 changes: 52 additions & 0 deletions vite.config.js
Original file line number Diff line number Diff line change
@@ -0,0 +1,52 @@
import { resolve } from 'path'
import { defineConfig } from 'vite'
import react from '@vitejs/plugin-react'
import cssInjectedByJsPlugin from 'vite-plugin-css-injected-by-js'
import replace from '@rollup/plugin-replace'
import copy from 'rollup-plugin-copy'

export default defineConfig(({ command, mode }) => {
if (mode !== 'production' || command === 'serve') {
return {
plugins: [react()],
server: {
port: process.env.PORT || 8080,
host: '0.0.0.0'
},
preview: {
port: process.env.PORT || 8080,
host: '0.0.0.0'
},
publicDir: 'public'
}
}
return {
plugins: [
react(),
cssInjectedByJsPlugin(),
replace({
'process.env.NODE_ENV': JSON.stringify(mode),
}),
// The `rollup-plugin-copy` plugin is not necessary if you are not need to run in `preview` mode, but I suggest to test in this mode for safe.
copy({
targets: [{
src: 'index.html',
dest: 'dist',
transform: (contents, filename) => contents.toString().replace('<script type="module" src="./src/main.js"></script>', '<script src="./main.js"></script><script>CMS.registerWidget("test", window.StarterControl, window.StarterPreview);</script>')
}],
hook: "writeBundle"
})
],
build: {
lib: {
entry: resolve(__dirname, 'src/main.js'),
name: 'main',
fileName: (format, entryName) => {
return format === 'iife' ? "main.js" : `main.${format}.js`
},
formats: ['iife'], // You can add other formats if you need.
},
sourcemap: true
}
}
})